diff --git a/src/css/types.rs b/src/css/types.rs index d2d3f31..7f7bbcd 100644 --- a/src/css/types.rs +++ b/src/css/types.rs @@ -62,7 +62,7 @@ pub enum Unit { Px, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Copy)] pub struct Color { pub r: u8, pub g: u8, diff --git a/src/layout.rs b/src/layout.rs index 32eb75d..af3df72 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -2,7 +2,7 @@ use std::default::Default; use crate::{style::{StyledNode, Display}, css::types::{Value, Unit}}; -use self::BoxType::{AnonymousBlock, InlineNode, BlockNode}; +pub use self::BoxType::{AnonymousBlock, InlineNode, BlockNode}; #[derive(Debug, Default, Copy, Clone)] pub struct Dimensions { diff --git a/src/main.rs b/src/main.rs index 58f9d3b..9fbfa45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ pub mod html; pub mod css; pub mod style; pub mod layout; +pub mod painting; fn main() { // html 解析 diff --git a/src/painting.rs b/src/painting.rs new file mode 100644 index 0000000..330fc50 --- /dev/null +++ b/src/painting.rs @@ -0,0 +1,138 @@ +use std::vec; + +use crate::{layout::{Rect, LayoutBox, BlockNode, InlineNode}, css::types::{Color, Value}}; + +type DisplayList = Vec; + +enum DisplayCommand { + SolidColor(Color, Rect) +} + +pub struct Canvas { + pixels: Vec, + width: usize, + height: usize, +} + +pub fn paint(layout_root: &LayoutBox, bounds: Rect) -> Canvas { + let display_list = build_display_list(layout_root); + let mut canvas = Canvas::new(bounds.width as usize, bounds.height as usize); + for item in display_list { + canvas.paint_item(&item); + } + canvas +} + +fn build_display_list(layout_root: &LayoutBox) -> DisplayList { + let mut list = Vec::new(); + render_layout_box(&mut list, layout_root); + return list; +} + +fn render_layout_box(list: &mut DisplayList, layout_box: &LayoutBox) { + render_background(list, layout_box); + render_borders(list, layout_box); + + for child in &layout_box.children { + render_layout_box(list, layout_box); + } +} + +fn render_background(list: &mut DisplayList, layout_box: &LayoutBox) { + get_color(layout_box, "background").map( + |color| list.push(DisplayCommand::SolidColor(color, layout_box.dimensions.border_box())) + ); +} + +fn get_color(layout_box: &LayoutBox, name: &str) -> Option { + match layout_box.box_type { + BlockNode(style) | InlineNode(style) => match style.value(name) { + Some(Value::ColorValue(color)) => Some(color), + _ => None + } + _ => None + } +} + +fn render_borders(list: &mut DisplayList, layout_box: &LayoutBox) { + let color = match get_color(layout_box, "border-color") { + Some(color) => color, + _ => return + }; + + let d = &layout_box.dimensions; + let border_box = d.border_box(); + + // left border + list.push(DisplayCommand::SolidColor(color, Rect { + x: border_box.x, + y: border_box.y, + width: d.border.left, + height: border_box.height, + })); + + // right border + list.push(DisplayCommand::SolidColor(color, Rect { + x: border_box.x + border_box.width - d.border.right, + y: border_box.y, + width: d.border.right, + height: border_box.height, + })); + + // top border + list.push(DisplayCommand::SolidColor(color, Rect { + x: border_box.x, + y: border_box.y, + width: border_box.width, + height: d.border.top, + })); + + // bottom border + list.push(DisplayCommand::SolidColor(color, Rect { + x: border_box.x, + y: border_box.y + border_box.height - d.border.bottom, + width: border_box.width, + height: d.border.bottom, + })); +} + +impl Canvas { + // 创建白色画布 + fn new(width: usize, height: usize) -> Canvas { + let white = Color { r: 255, g: 255, b: 255, a: 255 }; + Canvas { + pixels: vec![white; width * height], + width, + height, + } + } + + // 绘制矩形 + fn paint_item(&mut self, item: &DisplayCommand) { + match item { + &DisplayCommand::SolidColor(color, rect) => { + // 剪切矩形到画布边界 + let x0 = rect.x.clamp(0.0, self.width as f32) as usize; + let y0 = rect.y.clamp(0.0, self.height as f32) as usize; + let x1 = (rect.x + rect.width).clamp(0.0, self.width as f32) as usize; + let y1 = (rect.y + rect.height).clamp(0.0, self.height as f32) as usize; + + for y in y0 .. y1 { + for x in x0 .. x1 { + self.pixels[y * self.width + x] = color; + } + } + } + } + } +} + +trait Clamp { + fn clamp(self, lower: Self, upper: Self) -> Self; +} + +impl Clamp for f32 { + fn clamp(self, lower: Self, upper: Self) -> Self { + self.max(lower).min(upper) + } +} \ No newline at end of file