Skip to content

Commit

Permalink
Improve sizing of replaced elements
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 da893ea commit ca99a66
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 46 deletions.
30 changes: 15 additions & 15 deletions packages/blitz-dom/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use style::values::computed::length_percentage::CalcLengthPercentage;
use style::values::computed::CSSPixelLength;
use taffy::{
compute_block_layout, compute_cached_layout, compute_flexbox_layout, compute_grid_layout,
compute_leaf_layout, prelude::*, FlexDirection, LayoutPartialTree, NodeId, ResolveOrZero,
RoundTree, Style, TraversePartialTree, TraverseTree,
compute_leaf_layout, prelude::*, CollapsibleMarginSet, FlexDirection, LayoutPartialTree,
NodeId, ResolveOrZero, RoundTree, Style, TraversePartialTree, TraverseTree,
};

pub(crate) mod construct;
Expand Down Expand Up @@ -258,22 +258,22 @@ impl LayoutPartialTree for BaseDocument {
attr_size,
};

let computed = compute_leaf_layout(
inputs,
let computed = replaced_measure_function(
inputs.known_dimensions,
inputs.parent_size,
&replaced_context,
&node.style,
resolve_calc_value,
|known_dimensions, _available_space| {
replaced_measure_function(
known_dimensions,
inputs.parent_size,
&replaced_context,
&node.style,
false,
)
},
false,
);

return computed;
return taffy::LayoutOutput {
size: computed,
content_size: computed,
first_baselines: taffy::Point::NONE,
top_margin: CollapsibleMarginSet::ZERO,
bottom_margin: CollapsibleMarginSet::ZERO,
margins_can_collapse_through: false,
};
}

if node.is_table_root {
Expand Down
177 changes: 148 additions & 29 deletions packages/blitz-dom/src/layout/replaced.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use taffy::{MaybeMath, MaybeResolve};
use taffy::{BoxSizing, CoreStyle as _, MaybeMath, MaybeResolve, ResolveOrZero as _, Size};

use crate::layout::resolve_calc_value;

Expand All @@ -14,53 +14,172 @@ pub fn replaced_measure_function(
image_context: &ReplacedContext,
style: &taffy::Style,
_debug: bool,
) -> taffy::geometry::Size<f32> {
) -> taffy::Size<f32> {
let inherent_size = image_context.inherent_size;

let padding = style
.padding()
.resolve_or_zero(parent_size.width, resolve_calc_value);
let border = style
.border()
.resolve_or_zero(parent_size.width, resolve_calc_value);
let padding_border = padding + border;
let pb_sum = Size {
width: padding_border.left + padding_border.right,
height: padding_border.top + padding_border.bottom,
};
let box_sizing_adjustment = if style.box_sizing() == BoxSizing::ContentBox {
pb_sum
} else {
Size::ZERO
};

// Use aspect_ratio from style, fall back to inherent aspect ratio
let s_aspect_ratio = style.aspect_ratio;
let aspect_ratio = s_aspect_ratio.unwrap_or_else(|| inherent_size.width / inherent_size.height);
let inv_aspect_ratio = 1.0 / aspect_ratio;

// Resolve sizes
let style_size = style
.size
.maybe_resolve(parent_size, resolve_calc_value)
.maybe_apply_aspect_ratio(Some(aspect_ratio));
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.maybe_sub(box_sizing_adjustment);
let min_size = style
.min_size
.maybe_resolve(parent_size, resolve_calc_value)
.maybe_apply_aspect_ratio(Some(aspect_ratio));
.maybe_sub(box_sizing_adjustment);
let max_size = style
.max_size
.maybe_resolve(parent_size, resolve_calc_value)
.maybe_apply_aspect_ratio(Some(aspect_ratio));
let attr_size = image_context
.attr_size
.maybe_apply_aspect_ratio(Some(aspect_ratio));
.maybe_max(min_size)
.maybe_sub(box_sizing_adjustment);
let attr_size = image_context.attr_size;

if known_dimensions.width.is_some() | known_dimensions.height.is_some() {
return known_dimensions
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap());
}
let unclamped_size = 'size: {
if known_dimensions.width.is_some() | known_dimensions.height.is_some() {
break 'size known_dimensions
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap());
}

if style_size.width.is_some() | style_size.height.is_some() {
return style_size
.maybe_clamp(min_size, max_size)
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap());
}
if style_size.width.is_some() | style_size.height.is_some() {
break 'size style_size
// .maybe_clamp(min_size, max_size)
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap());
}

if attr_size.width.is_some() | attr_size.height.is_some() {
break 'size attr_size
// .maybe_clamp(min_size, max_size)
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap());
}

if attr_size.width.is_some() | attr_size.height.is_some() {
return attr_size
.maybe_clamp(min_size, max_size)
inherent_size
// .maybe_clamp(min_size, max_size)
.map(Some)
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap());
}
.map(|s| s.unwrap())
};

inherent_size
.maybe_clamp(min_size, max_size)
.map(Some)
.maybe_apply_aspect_ratio(Some(aspect_ratio))
.map(|s| s.unwrap())
// Violations
let w_min = unclamped_size.width < min_size.width.unwrap_or(0.0);
let w_max = unclamped_size.width > max_size.width.unwrap_or(f32::INFINITY);
let h_min = unclamped_size.height < min_size.height.unwrap_or(0.0);
let h_max = unclamped_size.height > max_size.height.unwrap_or(f32::INFINITY);

// Clamp following rules in table at
// https://www.w3.org/TR/CSS22/visudet.html#min-max-widths
let size = match (w_min, w_max, h_min, h_max) {
// No constraint violation
(false, false, false, false) => unclamped_size,
// w > max-width
(false, true, false, false) => {
let max_width = max_size.width.unwrap();
Size {
width: max_width,
height: (max_width * inv_aspect_ratio).maybe_max(min_size.height),
}
}
// w < min-width
(true, false, false, false) => {
let min_width = min_size.width.unwrap();
Size {
width: min_width,
height: (min_width * inv_aspect_ratio).maybe_min(max_size.height),
}
}
// h > max-height
(false, false, false, true) => {
let max_height = max_size.height.unwrap();
Size {
width: (max_height * aspect_ratio).maybe_max(min_size.width),
height: max_height,
}
}
// h < min-height
(false, false, true, false) => {
let min_height = min_size.height.unwrap();
Size {
width: (min_height * aspect_ratio).maybe_min(max_size.width),
height: min_height,
}
}
// (w > max-width) and (h > max-height)
(false, true, false, true) => {
let max_width = max_size.width.unwrap();
let max_height = max_size.height.unwrap();
if max_width / unclamped_size.width <= max_height / unclamped_size.height {
Size {
width: max_width,
height: (max_width * inv_aspect_ratio).maybe_max(min_size.height),
}
} else {
Size {
width: (max_height * aspect_ratio).maybe_max(min_size.width),
height: max_height,
}
}
}
// (w < min-width) and (h < min-height)
(true, false, true, false) => {
let min_width = min_size.width.unwrap();
let min_height = min_size.height.unwrap();
if min_width / unclamped_size.width <= min_height / unclamped_size.height {
Size {
width: (min_height * aspect_ratio).maybe_min(max_size.width),
height: min_height,
}
} else {
Size {
width: min_width,
height: (min_width * inv_aspect_ratio).maybe_min(max_size.height),
}
}
}
// (w < min-width) and (h > max-height)
(true, false, false, true) => {
let min_width = min_size.width.unwrap();
let max_height = max_size.height.unwrap();
Size {
width: min_width,
height: max_height,
}
}
// (w < min-width) and (h > max-height)
(false, true, true, false) => {
let max_width = max_size.width.unwrap();
let min_height = min_size.height.unwrap();
Size {
width: max_width,
height: min_height,
}
}

_ => unreachable!("Max was already floored by min, so we cannot have both a min and a max violation in the same axis")
};

size + pb_sum
}
10 changes: 8 additions & 2 deletions packages/blitz-renderer-vello/src/renderer/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,25 +981,31 @@ impl ElementCx<'_> {
fn draw_image(&self, scene: &mut Scene) {
let width = self.frame.content_box.width() as u32;
let height = self.frame.content_box.height() as u32;
let x = self.frame.content_box.origin().x;
let y = self.frame.content_box.origin().y;
let transform = self.transform.then_translate(Vec2 { x, y });

if let Some(image_data) = self.element.raster_image_data() {
ensure_resized_image(image_data, width, height);
let resized_image = image_data.resized_image.borrow();
scene.draw_image(resized_image.as_ref().unwrap(), self.transform);
scene.draw_image(resized_image.as_ref().unwrap(), transform);
}
}

fn draw_raster_bg_image(&self, scene: &mut Scene, idx: usize) {
let width = self.frame.padding_box.width() as u32;
let height = self.frame.padding_box.height() as u32;
let x = self.frame.content_box.origin().x;
let y = self.frame.content_box.origin().y;
let transform = self.transform.then_translate(Vec2 { x, y });

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

if let Some(Some(bg_image)) = bg_image.as_ref() {
if let ImageData::Raster(image_data) = &bg_image.image {
ensure_resized_image(image_data, width, height);
let resized_image = image_data.resized_image.borrow();
scene.draw_image(resized_image.as_ref().unwrap(), self.transform);
scene.draw_image(resized_image.as_ref().unwrap(), transform);
}
}
}
Expand Down

0 comments on commit ca99a66

Please sign in to comment.