Skip to content

Commit

Permalink
feat: 添加渲染函数
Browse files Browse the repository at this point in the history
  • Loading branch information
NameWjp committed Feb 9, 2023
1 parent 71f1969 commit 6e1af74
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/css/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod html;
pub mod css;
pub mod style;
pub mod layout;
pub mod painting;

fn main() {
// html 解析
Expand Down
138 changes: 138 additions & 0 deletions src/painting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use std::vec;

use crate::{layout::{Rect, LayoutBox, BlockNode, InlineNode}, css::types::{Color, Value}};

type DisplayList = Vec<DisplayCommand>;

enum DisplayCommand {
SolidColor(Color, Rect)
}

pub struct Canvas {
pixels: Vec<Color>,
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<Color> {
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)
}
}

0 comments on commit 6e1af74

Please sign in to comment.