Skip to content

Commit

Permalink
Render images in content box not padding box
Browse files Browse the repository at this point in the history
Signed-off-by: Nico Burns <[email protected]>
  • Loading branch information
nicoburns committed Jan 31, 2025
1 parent c1a7ecf commit da893ea
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ use vello::kurbo::{Arc, BezPath, Ellipse, PathEl, Point, Rect, Shape, Vec2};
///
#[derive(Debug, Clone)]
pub struct ElementFrame {
pub outer_rect: Rect,
pub inner_rect: Rect,
pub border_box: Rect,
pub padding_box: Rect,
pub content_box: Rect,
pub outline_width: f64,

pub border_top_width: f64,
Expand All @@ -42,53 +43,60 @@ pub struct ElementFrame {
impl ElementFrame {
#[rustfmt::skip]
pub fn new(style: &ComputedValues, layout: &Layout, scale: f64) -> Self {
let (border, outline) = (style.get_border(), style.get_outline());

// let scale = 1.0;
let s_border = style.get_border();
let outline = style.get_outline();

// Resolve and rescale
// We have to scale since document pixels are not same same as rendered pixels
let border_top_width = scale * border.border_top_width.to_f64_px();
let border_left_width = scale * border.border_left_width.to_f64_px();
let border_right_width = scale * border.border_right_width.to_f64_px();
let border_bottom_width = scale * border.border_bottom_width.to_f64_px();
// let border_top_width = scale * border.border_top_width.to_f64_px();
// let border_left_width = scale * border.border_left_width.to_f64_px();
// let border_right_width = scale * border.border_right_width.to_f64_px();
// let border_bottom_width = scale * border.border_bottom_width.to_f64_px();
let border = layout.border.map(|p| p as f64 * scale);
let padding = layout.padding.map(|p| p as f64 * scale);
let outline_width = scale * outline.outline_width.to_f64_px();

let width: f64 = layout.size.width.into();
let height: f64 = layout.size.height.into();
let width = scale * width;
let height = scale * height;

let outer_rect = Rect::new(0.0, 0.0, width, height);
let inner_rect = Rect::new(
border_left_width,
border_top_width,
width - border_right_width,
height - border_bottom_width,
let border_box = Rect::new(0.0, 0.0, width, height);
let padding_box = Rect::new(
border.left,
border.top,
width - border.right,
height - border.bottom,
);
let content_box = Rect::new(
border.left + padding.left,
border.top + padding.top,
width - border.right - padding.right,
height - border.bottom - padding.bottom,
);

// Resolve the radii to a length. need to downscale since the radii are in document pixels
let pixel_width = CSSPixelLength::new((inner_rect.width() / scale) as _);
let pixel_height = CSSPixelLength::new((inner_rect.height() / scale) as _);
let pixel_width = CSSPixelLength::new((padding_box.width() / scale) as _);
let pixel_height = CSSPixelLength::new((padding_box.height() / scale) as _);

let mut border_top_left_radius_width = scale * border.border_top_left_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_top_left_radius_height = scale * border.border_top_left_radius.0.height.0.resolve(pixel_height).px() as f64;
let mut border_top_left_radius_width = scale * s_border.border_top_left_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_top_left_radius_height = scale * s_border.border_top_left_radius.0.height.0.resolve(pixel_height).px() as f64;

let mut border_top_right_radius_width = scale * border.border_top_right_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_top_right_radius_height = scale * border.border_top_right_radius.0.height.0.resolve(pixel_height).px() as f64;
let mut border_top_right_radius_width = scale * s_border.border_top_right_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_top_right_radius_height = scale * s_border.border_top_right_radius.0.height.0.resolve(pixel_height).px() as f64;

let mut border_bottom_left_radius_width = scale * border.border_bottom_left_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_bottom_left_radius_height = scale * border.border_bottom_left_radius.0.height.0.resolve(pixel_height).px() as f64;
let mut border_bottom_left_radius_width = scale * s_border.border_bottom_left_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_bottom_left_radius_height = scale * s_border.border_bottom_left_radius.0.height.0.resolve(pixel_height).px() as f64;

let mut border_bottom_right_radius_width = scale * border.border_bottom_right_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_bottom_right_radius_height = scale * border.border_bottom_right_radius.0.height.0.resolve(pixel_height).px() as f64;
let mut border_bottom_right_radius_width = scale * s_border.border_bottom_right_radius.0.width.0.resolve(pixel_width).px() as f64;
let mut border_bottom_right_radius_height = scale * s_border.border_bottom_right_radius.0.height.0.resolve(pixel_height).px() as f64;

// Correct the border radii if they are too big if two border radii would intersect, then we need to shrink
// ALL border radii by the same factor such that they do not
let top_overlap_factor = inner_rect.width() / (border_top_left_radius_width + border_top_right_radius_width);
let bottom_overlap_factor = inner_rect.width() / (border_bottom_left_radius_width + border_bottom_right_radius_width);
let left_overlap_factor = inner_rect.height() / (border_top_left_radius_height + border_bottom_left_radius_height);
let right_overlap_factor = inner_rect.height() / (border_top_right_radius_height + border_bottom_right_radius_height);
let top_overlap_factor = padding_box.width() / (border_top_left_radius_width + border_top_right_radius_width);
let bottom_overlap_factor = padding_box.width() / (border_bottom_left_radius_width + border_bottom_right_radius_width);
let left_overlap_factor = padding_box.height() / (border_top_left_radius_height + border_bottom_left_radius_height);
let right_overlap_factor = padding_box.height() / (border_top_right_radius_height + border_bottom_right_radius_height);

let min_factor = top_overlap_factor.min(bottom_overlap_factor).min(left_overlap_factor).min(right_overlap_factor).min(1.0);
if min_factor < 1.0 {
Expand All @@ -103,13 +111,14 @@ impl ElementFrame {
}

Self {
inner_rect,
outer_rect,
padding_box,
border_box,
content_box,
outline_width,
border_top_width,
border_left_width,
border_right_width,
border_bottom_width,
border_top_width: border.top,
border_left_width: border.left,
border_right_width: border.right,
border_bottom_width: border.bottom,
border_top_left_radius_width,
border_top_left_radius_height,
border_top_right_radius_width,
Expand Down Expand Up @@ -241,7 +250,7 @@ impl ElementFrame {
}

fn corner(&self, corner: Corner, side: ArcSide) -> Point {
let Rect { x0, y0, x1, y1 } = self.outer_rect;
let Rect { x0, y0, x1, y1 } = self.border_box;

let (x, y) = match corner {
Corner::TopLeft => match side {
Expand Down Expand Up @@ -274,7 +283,7 @@ impl ElementFrame {
}

fn shadow_clip_corner(&self, corner: Corner, offset: f64) -> Point {
let Rect { x0, y0, x1, y1 } = self.outer_rect;
let Rect { x0, y0, x1, y1 } = self.border_box;

let (x, y) = match corner {
Corner::TopLeft => (x0 - offset, y0 - offset),
Expand Down Expand Up @@ -459,7 +468,7 @@ impl ElementFrame {
fn ellipse(&self, corner: Corner, side: ArcSide) -> Ellipse {
use {Corner::*, ArcSide::*};
let ElementFrame {
outer_rect: rect,
border_box: rect,
border_top_width,
border_left_width,
border_right_width,
Expand Down
70 changes: 35 additions & 35 deletions packages/blitz-renderer-vello/src/renderer/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,11 +547,11 @@ impl VelloSceneGenerator<'_> {
let origin_translation = Affine::translate(Vec2 {
x: transform_origin
.horizontal
.resolve(CSSPixelLength::new(frame.outer_rect.width() as f32))
.resolve(CSSPixelLength::new(frame.border_box.width() as f32))
.px() as f64,
y: transform_origin
.vertical
.resolve(CSSPixelLength::new(frame.outer_rect.width() as f32))
.resolve(CSSPixelLength::new(frame.border_box.width() as f32))
.px() as f64,
});
let kurbo_transform =
Expand Down Expand Up @@ -899,14 +899,14 @@ impl ElementCx<'_> {
return;
};

let width = self.frame.inner_rect.width() as u32;
let height = self.frame.inner_rect.height() as u32;
let width = self.frame.padding_box.width() as u32;
let height = self.frame.padding_box.height() as u32;
let svg_size = svg.size();

let x_scale = width as f64 / svg_size.width() as f64;
let y_scale = height as f64 / svg_size.height() as f64;

let box_inset = self.frame.inner_rect.origin();
let box_inset = self.frame.padding_box.origin();
let transform = Affine::translate((
self.pos.x * self.scale + box_inset.x,
self.pos.y * self.scale + box_inset.y,
Expand All @@ -930,8 +930,8 @@ impl ElementCx<'_> {
return;
};

let frame_w = self.frame.inner_rect.width() as f32;
let frame_h = self.frame.inner_rect.height() as f32;
let frame_w = self.frame.padding_box.width() as f32;
let frame_h = self.frame.padding_box.height() as f32;

let svg_size = svg.size();
let bg_size = compute_background_size(
Expand Down Expand Up @@ -979,8 +979,8 @@ impl ElementCx<'_> {
}

fn draw_image(&self, scene: &mut Scene) {
let width = self.frame.inner_rect.width() as u32;
let height = self.frame.inner_rect.height() as u32;
let width = self.frame.content_box.width() as u32;
let height = self.frame.content_box.height() as u32;

if let Some(image_data) = self.element.raster_image_data() {
ensure_resized_image(image_data, width, height);
Expand All @@ -990,8 +990,8 @@ impl ElementCx<'_> {
}

fn draw_raster_bg_image(&self, scene: &mut Scene, idx: usize) {
let width = self.frame.inner_rect.width() as u32;
let height = self.frame.inner_rect.height() as u32;
let width = self.frame.padding_box.width() as u32;
let height = self.frame.padding_box.height() as u32;

let bg_image = self.element.background_images.get(idx);

Expand All @@ -1006,7 +1006,7 @@ impl ElementCx<'_> {

fn stroke_devtools(&self, scene: &mut Scene) {
if self.devtools.show_layout {
let shape = &self.frame.outer_rect;
let shape = &self.frame.border_box;
let stroke = Stroke::new(self.scale);

let stroke_color = match self.node.style.display {
Expand Down Expand Up @@ -1099,12 +1099,12 @@ impl ElementCx<'_> {
items: &[GradientItem<LengthPercentage>],
flags: GradientFlags,
) {
let bb = self.frame.outer_rect.bounding_box();
let bb = self.frame.border_box.bounding_box();
let current_color = self.style.clone_color();

let shape = self.frame.frame();
let center = bb.center();
let rect = self.frame.inner_rect;
let rect = self.frame.padding_box;
let (start, end) = match direction {
LineDirection::Angle(angle) => {
let angle = -angle.radians64() + std::f64::consts::PI;
Expand All @@ -1115,12 +1115,12 @@ impl ElementCx<'_> {
}
LineDirection::Horizontal(horizontal) => {
let start = Point::new(
self.frame.inner_rect.x0,
self.frame.inner_rect.y0 + rect.height() / 2.0,
self.frame.padding_box.x0,
self.frame.padding_box.y0 + rect.height() / 2.0,
);
let end = Point::new(
self.frame.inner_rect.x1,
self.frame.inner_rect.y0 + rect.height() / 2.0,
self.frame.padding_box.x1,
self.frame.padding_box.y0 + rect.height() / 2.0,
);
match horizontal {
HorizontalPositionKeyword::Right => (start, end),
Expand All @@ -1129,12 +1129,12 @@ impl ElementCx<'_> {
}
LineDirection::Vertical(vertical) => {
let start = Point::new(
self.frame.inner_rect.x0 + rect.width() / 2.0,
self.frame.inner_rect.y0,
self.frame.padding_box.x0 + rect.width() / 2.0,
self.frame.padding_box.y0,
);
let end = Point::new(
self.frame.inner_rect.x0 + rect.width() / 2.0,
self.frame.inner_rect.y1,
self.frame.padding_box.x0 + rect.width() / 2.0,
self.frame.padding_box.y1,
);
match vertical {
VerticalPositionKeyword::Top => (end, start),
Expand All @@ -1144,18 +1144,18 @@ impl ElementCx<'_> {
LineDirection::Corner(horizontal, vertical) => {
let (start_x, end_x) = match horizontal {
HorizontalPositionKeyword::Right => {
(self.frame.inner_rect.x0, self.frame.inner_rect.x1)
(self.frame.padding_box.x0, self.frame.padding_box.x1)
}
HorizontalPositionKeyword::Left => {
(self.frame.inner_rect.x1, self.frame.inner_rect.x0)
(self.frame.padding_box.x1, self.frame.padding_box.x0)
}
};
let (start_y, end_y) = match vertical {
VerticalPositionKeyword::Top => {
(self.frame.inner_rect.y1, self.frame.inner_rect.y0)
(self.frame.padding_box.y1, self.frame.padding_box.y0)
}
VerticalPositionKeyword::Bottom => {
(self.frame.inner_rect.y0, self.frame.inner_rect.y1)
(self.frame.padding_box.y0, self.frame.padding_box.y1)
}
};
(Point::new(start_x, start_y), Point::new(end_x, end_y))
Expand Down Expand Up @@ -1410,7 +1410,7 @@ impl ElementCx<'_> {
// Fill the color
scene.draw_blurred_rounded_rect(
transform,
elem_cx.frame.outer_rect,
elem_cx.frame.border_box,
shadow_color,
radius,
shadow.base.blur.px() as f64,
Expand Down Expand Up @@ -1461,7 +1461,7 @@ impl ElementCx<'_> {
// Fill the color
scene.draw_blurred_rounded_rect(
transform,
self.frame.outer_rect,
self.frame.border_box,
shadow_color,
radius,
shadow.base.blur.px() as f64,
Expand Down Expand Up @@ -1639,7 +1639,7 @@ impl ElementCx<'_> {
flags: GradientFlags,
) {
let bez_path = self.frame.frame();
let rect = self.frame.inner_rect;
let rect = self.frame.padding_box;
let repeating = flags.contains(GradientFlags::REPEATING);
let current_color = self.style.clone_color();

Expand Down Expand Up @@ -1761,7 +1761,7 @@ impl ElementCx<'_> {
flags: GradientFlags,
) {
let bez_path = self.frame.frame();
let rect = self.frame.inner_rect;
let rect = self.frame.padding_box;
let current_color = self.style.clone_color();

let repeating = flags.contains(GradientFlags::REPEATING);
Expand Down Expand Up @@ -1808,12 +1808,12 @@ impl ElementCx<'_> {
rect: Rect,
) -> Vec2 {
Vec2::new(
self.frame.inner_rect.x0
self.frame.padding_box.x0
+ position
.horizontal
.resolve(CSSPixelLength::new(rect.width() as f32))
.px() as f64,
self.frame.inner_rect.y0
self.frame.padding_box.y0
+ position
.vertical
.resolve(CSSPixelLength::new(rect.height() as f32))
Expand All @@ -1837,14 +1837,14 @@ impl ElementCx<'_> {

let scale = (self
.frame
.outer_rect
.border_box
.width()
.min(self.frame.outer_rect.height())
.min(self.frame.border_box.height())
- 4.0)
.max(0.0)
/ 16.0;

let frame = self.frame.outer_rect.to_rounded_rect(scale * 2.0);
let frame = self.frame.border_box.to_rounded_rect(scale * 2.0);

let attr_type = self.node.attr(local_name!("type"));

Expand Down

0 comments on commit da893ea

Please sign in to comment.