Skip to content

Commit ef0c390

Browse files
kalenikaliaksandrawesomekling
authored andcommitted
LibWeb: Resolve CSS transform properties during layout commit
Now, instead of resolving "transform" and "transform-origin" during the construction of the stacking context tree, we do so during the layout commit. This is part of a refactoring effort to make the paintable tree independent from the layout tree.
1 parent aab3cd3 commit ef0c390

File tree

5 files changed

+57
-42
lines changed

5 files changed

+57
-42
lines changed

Userland/Libraries/LibWeb/Layout/LayoutState.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,38 @@ void LayoutState::resolve_text_shadows(Vector<Painting::PaintableWithLines&> con
390390
}
391391
}
392392

393+
void LayoutState::resolve_css_transform()
394+
{
395+
for (auto& it : used_values_per_layout_node) {
396+
auto& used_values = *it.value;
397+
if (!used_values.node().is_box())
398+
continue;
399+
400+
auto const& box = static_cast<Layout::Box const&>(used_values.node());
401+
if (!box.paintable_box())
402+
continue;
403+
404+
auto& paintable_box = const_cast<Painting::PaintableBox&>(*box.paintable_box());
405+
auto const& transformations = box.computed_values().transformations();
406+
if (transformations.is_empty())
407+
continue;
408+
409+
auto matrix = Gfx::FloatMatrix4x4::identity();
410+
for (auto const& transform : transformations)
411+
matrix = matrix * transform.to_matrix(paintable_box).release_value();
412+
413+
paintable_box.set_transform(matrix);
414+
415+
auto const& style_value = box.computed_values().transform_origin();
416+
// FIXME: respect transform-box property
417+
auto const& reference_box = paintable_box.absolute_border_box_rect();
418+
auto x = reference_box.left() + style_value.x.to_px(box, reference_box.width());
419+
auto y = reference_box.top() + style_value.y.to_px(box, reference_box.height());
420+
421+
paintable_box.set_transform_origin({ x, y });
422+
}
423+
}
424+
393425
void LayoutState::commit(Box& root)
394426
{
395427
// Only the top-level LayoutState should ever be committed.
@@ -502,6 +534,7 @@ void LayoutState::commit(Box& root)
502534
resolve_border_radii();
503535
resolve_box_shadow_data();
504536
resolve_text_shadows(paintables_with_lines);
537+
resolve_css_transform();
505538
}
506539

507540
void LayoutState::UsedValues::set_node(NodeWithStyle& node, UsedValues const* containing_block_used_values)

Userland/Libraries/LibWeb/Layout/LayoutState.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ struct LayoutState {
189189
void resolve_border_radii();
190190
void resolve_box_shadow_data();
191191
void resolve_text_shadows(Vector<Painting::PaintableWithLines&> const& paintables_with_lines);
192+
void resolve_css_transform();
192193
};
193194

194195
}

Userland/Libraries/LibWeb/Painting/PaintableBox.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ class PaintableBox : public Paintable {
185185
void set_box_shadow_data(Vector<ShadowData> box_shadow_data) { m_box_shadow_data = move(box_shadow_data); }
186186
Vector<ShadowData> const& box_shadow_data() const { return m_box_shadow_data; }
187187

188+
void set_transform(Gfx::FloatMatrix4x4 transform) { m_transform = transform; }
189+
Gfx::FloatMatrix4x4 const& transform() const { return m_transform; }
190+
191+
void set_transform_origin(CSSPixelPoint transform_origin) { m_transform_origin = transform_origin; }
192+
CSSPixelPoint const& transform_origin() const { return m_transform_origin; }
193+
188194
protected:
189195
explicit PaintableBox(Layout::Box const&);
190196

@@ -219,6 +225,8 @@ class PaintableBox : public Paintable {
219225

220226
BorderRadiiData m_border_radii_data;
221227
Vector<ShadowData> m_box_shadow_data;
228+
Gfx::FloatMatrix4x4 m_transform { Gfx::FloatMatrix4x4::identity() };
229+
CSSPixelPoint m_transform_origin;
222230
};
223231

224232
class PaintableWithLines : public PaintableBox {

Userland/Libraries/LibWeb/Painting/StackingContext.cpp

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ static void paint_node(Paintable const& paintable, PaintContext& context, PaintP
3333

3434
StackingContext::StackingContext(Paintable& paintable, StackingContext* parent, size_t index_in_tree_order)
3535
: m_paintable(paintable)
36-
, m_transform(combine_transformations(paintable.computed_values().transformations()))
37-
, m_transform_origin(compute_transform_origin())
3836
, m_parent(parent)
3937
, m_index_in_tree_order(index_in_tree_order)
4038
{
@@ -291,28 +289,13 @@ void StackingContext::paint_internal(PaintContext& context) const
291289
}
292290
}
293291

294-
Gfx::FloatMatrix4x4 StackingContext::combine_transformations(Vector<CSS::Transformation> const& transformations) const
295-
{
296-
// https://drafts.csswg.org/css-transforms-1/#WD20171130 says:
297-
// "No transform on non-replaced inline boxes, table-column boxes, and table-column-group boxes."
298-
// and https://www.w3.org/TR/css-transforms-2/ does not say anything about what to do with inline boxes.
299-
300-
auto matrix = Gfx::FloatMatrix4x4::identity();
301-
if (paintable().is_paintable_box()) {
302-
for (auto const& transform : transformations)
303-
matrix = matrix * transform.to_matrix(paintable_box()).release_value();
304-
305-
return matrix;
306-
}
307-
308-
return matrix;
309-
}
310-
311292
// FIXME: This extracts the affine 2D part of the full transformation matrix.
312293
// Use the whole matrix when we get better transformation support in LibGfx or use LibGL for drawing the bitmap
313294
Gfx::AffineTransform StackingContext::affine_transform_matrix() const
314295
{
315-
return Gfx::extract_2d_affine_transform(m_transform);
296+
if (paintable().is_paintable_box())
297+
return Gfx::extract_2d_affine_transform(paintable_box().transform());
298+
return Gfx::AffineTransform {};
316299
}
317300

318301
static Gfx::FloatMatrix4x4 matrix_with_scaled_translation(Gfx::FloatMatrix4x4 matrix, float scale)
@@ -342,14 +325,21 @@ void StackingContext::paint(PaintContext& context) const
342325
VERIFY_NOT_REACHED();
343326
}
344327

328+
auto transform_matrix = Gfx::FloatMatrix4x4::identity();
329+
Gfx::FloatPoint transform_origin;
330+
if (paintable().is_paintable_box()) {
331+
transform_matrix = paintable_box().transform();
332+
transform_origin = paintable_box().transform_origin().to_type<float>();
333+
}
334+
345335
RecordingPainter::PushStackingContextParams push_stacking_context_params {
346336
.opacity = opacity,
347337
.is_fixed_position = paintable().is_fixed_position(),
348338
.source_paintable_rect = source_paintable_rect,
349339
.image_rendering = paintable().computed_values().image_rendering(),
350340
.transform = {
351-
.origin = transform_origin().scaled(to_device_pixels_scale),
352-
.matrix = matrix_with_scaled_translation(transform_matrix(), to_device_pixels_scale),
341+
.origin = transform_origin.scaled(to_device_pixels_scale),
342+
.matrix = matrix_with_scaled_translation(transform_matrix, to_device_pixels_scale),
353343
},
354344
};
355345

@@ -374,19 +364,6 @@ void StackingContext::paint(PaintContext& context) const
374364
context.recording_painter().pop_stacking_context();
375365
}
376366

377-
Gfx::FloatPoint StackingContext::compute_transform_origin() const
378-
{
379-
if (!paintable().is_paintable_box())
380-
return {};
381-
382-
auto style_value = paintable().computed_values().transform_origin();
383-
// FIXME: respect transform-box property
384-
auto reference_box = paintable_box().absolute_border_box_rect();
385-
auto x = reference_box.left() + style_value.x.to_px(paintable().layout_node(), reference_box.width());
386-
auto y = reference_box.top() + style_value.y.to_px(paintable().layout_node(), reference_box.height());
387-
return { x.to_float(), y.to_float() };
388-
}
389-
390367
template<typename Callback>
391368
static TraversalDecision for_each_in_inclusive_subtree_within_same_stacking_context_in_reverse(Paintable const& paintable, Callback callback)
392369
{
@@ -420,7 +397,9 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
420397
if (!paintable().is_visible())
421398
return {};
422399

423-
auto transform_origin = this->transform_origin().to_type<CSSPixels>();
400+
CSSPixelPoint transform_origin { 0, 0 };
401+
if (paintable().is_paintable_box())
402+
transform_origin = paintable_box().transform_origin();
424403
// NOTE: This CSSPixels -> Float -> CSSPixels conversion is because we can't AffineTransform::map() a CSSPixelPoint.
425404
Gfx::FloatPoint offset_position {
426405
(position.x() - transform_origin.x()).to_float(),

Userland/Libraries/LibWeb/Painting/StackingContext.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class StackingContext {
3737
void paint(PaintContext&) const;
3838
Optional<HitTestResult> hit_test(CSSPixelPoint, HitTestType) const;
3939

40-
Gfx::FloatMatrix4x4 const& transform_matrix() const { return m_transform; }
4140
Gfx::AffineTransform affine_transform_matrix() const;
4241

4342
void dump(int indent = 0) const;
@@ -46,17 +45,12 @@ class StackingContext {
4645

4746
private:
4847
JS::NonnullGCPtr<Paintable> m_paintable;
49-
Gfx::FloatMatrix4x4 m_transform;
50-
Gfx::FloatPoint m_transform_origin;
5148
StackingContext* const m_parent { nullptr };
5249
Vector<StackingContext*> m_children;
5350
size_t m_index_in_tree_order { 0 };
5451

5552
static void paint_child(PaintContext&, StackingContext const&);
5653
void paint_internal(PaintContext&) const;
57-
Gfx::FloatMatrix4x4 combine_transformations(Vector<CSS::Transformation> const& transformations) const;
58-
Gfx::FloatPoint transform_origin() const { return m_transform_origin; }
59-
Gfx::FloatPoint compute_transform_origin() const;
6054
};
6155

6256
}

0 commit comments

Comments
 (0)