2020-06-15 17:29:35 +02:00
/*
2022-02-14 16:39:45 +01:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < kling @ serenityos . org >
2020-06-15 17:29:35 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-06-15 17:29:35 +02:00
*/
2022-03-18 01:29:20 +01:00
# include <AK/Debug.h>
2020-06-15 17:29:35 +02:00
# include <AK/QuickSort.h>
2021-01-01 16:42:44 +01:00
# include <AK/StringBuilder.h>
2022-03-18 01:29:20 +01:00
# include <LibGfx/AffineTransform.h>
# include <LibGfx/Matrix4x4.h>
2021-07-23 13:19:16 +03:00
# include <LibGfx/Painter.h>
2022-03-18 01:29:20 +01:00
# include <LibGfx/Rect.h>
2020-11-22 15:53:01 +01:00
# include <LibWeb/Layout/Box.h>
2021-09-08 11:27:46 +02:00
# include <LibWeb/Layout/InitialContainingBlock.h>
2022-02-14 16:39:45 +01:00
# include <LibWeb/Layout/ReplacedBox.h>
2022-03-10 23:13:37 +01:00
# include <LibWeb/Painting/PaintableBox.h>
2020-06-18 22:01:05 +02:00
# include <LibWeb/Painting/StackingContext.h>
2020-06-15 17:29:35 +02:00
2022-03-10 02:13:28 +01:00
namespace Web : : Painting {
2020-06-15 17:29:35 +02:00
2022-03-10 14:02:25 +01:00
static void paint_node ( Layout : : Node const & layout_node , PaintContext & context , PaintPhase phase )
{
2022-03-10 15:38:34 +01:00
if ( auto const * paintable = layout_node . paintable ( ) )
paintable - > paint ( context , phase ) ;
2022-03-10 14:02:25 +01:00
}
2022-03-10 02:13:28 +01:00
StackingContext : : StackingContext ( Layout : : Box & box , StackingContext * parent )
2020-06-15 17:29:35 +02:00
: m_box ( box )
, m_parent ( parent )
{
2021-02-23 20:42:32 +01:00
VERIFY ( m_parent ! = this ) ;
2022-03-13 16:19:54 +01:00
if ( m_parent )
2020-06-15 17:29:35 +02:00
m_parent - > m_children . append ( this ) ;
2022-03-13 16:19:54 +01:00
}
2020-06-15 17:29:35 +02:00
2022-03-13 16:19:54 +01:00
void StackingContext : : sort ( )
{
quick_sort ( m_children , [ ] ( auto & a , auto & b ) {
auto a_z_index = a - > m_box . computed_values ( ) . z_index ( ) . value_or ( 0 ) ;
auto b_z_index = b - > m_box . computed_values ( ) . z_index ( ) . value_or ( 0 ) ;
if ( a_z_index = = b_z_index )
return a - > m_box . is_before ( b - > m_box ) ;
return a_z_index < b_z_index ;
} ) ;
for ( auto * child : m_children )
child - > sort ( ) ;
2020-06-15 17:29:35 +02:00
}
2022-03-10 15:44:43 +01:00
void StackingContext : : paint_descendants ( PaintContext & context , Layout : : Node & box , StackingContextPaintPhase phase ) const
2020-06-15 17:29:35 +02:00
{
2022-03-10 14:02:25 +01:00
if ( phase = = StackingContextPaintPhase : : Foreground ) {
2022-03-10 15:50:57 +01:00
if ( auto * paintable = box . paintable ( ) )
paintable - > before_children_paint ( context , PaintPhase : : Foreground ) ;
2022-03-10 14:02:25 +01:00
}
2021-08-01 16:24:59 +02:00
2021-05-07 19:03:25 +03:00
box . for_each_child ( [ & ] ( auto & child ) {
2022-03-16 19:02:37 +01:00
// If `child` establishes its own stacking context, skip over it.
if ( is < Layout : : Box > ( child ) & & child . paintable ( ) & & static_cast < Layout : : Box const & > ( child ) . paint_box ( ) - > stacking_context ( ) )
2021-07-23 13:16:04 +03:00
return ;
2022-03-10 02:13:28 +01:00
bool child_is_inline_or_replaced = child . is_inline ( ) | | is < Layout : : ReplacedBox > ( child ) ;
2021-05-07 19:03:25 +03:00
switch ( phase ) {
case StackingContextPaintPhase : : BackgroundAndBorders :
2022-02-14 16:39:45 +01:00
if ( ! child_is_inline_or_replaced & & ! child . is_floating ( ) & & ! child . is_positioned ( ) ) {
2022-03-10 14:02:25 +01:00
paint_node ( child , context , PaintPhase : : Background ) ;
paint_node ( child , context , PaintPhase : : Border ) ;
2021-05-07 19:03:25 +03:00
paint_descendants ( context , child , phase ) ;
}
break ;
case StackingContextPaintPhase : : Floats :
if ( ! child . is_positioned ( ) ) {
if ( child . is_floating ( ) ) {
2022-03-10 14:02:25 +01:00
paint_node ( child , context , PaintPhase : : Background ) ;
paint_node ( child , context , PaintPhase : : Border ) ;
2021-05-07 19:03:25 +03:00
paint_descendants ( context , child , StackingContextPaintPhase : : BackgroundAndBorders ) ;
}
paint_descendants ( context , child , phase ) ;
}
break ;
2022-02-14 16:39:45 +01:00
case StackingContextPaintPhase : : BackgroundAndBordersForInlineLevelAndReplaced :
if ( ! child . is_positioned ( ) ) {
if ( child_is_inline_or_replaced ) {
2022-03-10 14:02:25 +01:00
paint_node ( child , context , PaintPhase : : Background ) ;
paint_node ( child , context , PaintPhase : : Border ) ;
2022-02-14 16:39:45 +01:00
paint_descendants ( context , child , StackingContextPaintPhase : : BackgroundAndBorders ) ;
}
paint_descendants ( context , child , phase ) ;
}
break ;
2021-05-07 19:03:25 +03:00
case StackingContextPaintPhase : : Foreground :
if ( ! child . is_positioned ( ) ) {
2022-03-10 14:02:25 +01:00
paint_node ( child , context , PaintPhase : : Foreground ) ;
2021-05-07 19:03:25 +03:00
paint_descendants ( context , child , phase ) ;
}
break ;
case StackingContextPaintPhase : : FocusAndOverlay :
if ( context . has_focus ( ) ) {
2022-03-10 14:02:25 +01:00
paint_node ( child , context , PaintPhase : : FocusOutline ) ;
2021-05-07 19:03:25 +03:00
}
2022-03-10 14:02:25 +01:00
paint_node ( child , context , PaintPhase : : Overlay ) ;
2021-05-07 19:03:25 +03:00
paint_descendants ( context , child , phase ) ;
break ;
}
} ) ;
2021-08-01 16:24:59 +02:00
2022-03-10 14:02:25 +01:00
if ( phase = = StackingContextPaintPhase : : Foreground ) {
2022-03-10 15:50:57 +01:00
if ( auto * paintable = box . paintable ( ) )
paintable - > after_children_paint ( context , PaintPhase : : Foreground ) ;
2022-03-10 14:02:25 +01:00
}
2021-05-07 19:03:25 +03:00
}
2022-03-10 15:44:43 +01:00
void StackingContext : : paint_internal ( PaintContext & context ) const
2021-05-07 19:03:25 +03:00
{
// For a more elaborate description of the algorithm, see CSS 2.1 Appendix E
// Draw the background and borders for the context root (steps 1, 2)
2022-03-10 14:02:25 +01:00
paint_node ( m_box , context , PaintPhase : : Background ) ;
paint_node ( m_box , context , PaintPhase : : Border ) ;
2021-05-07 19:03:25 +03:00
// Draw positioned descendants with negative z-indices (step 3)
for ( auto * child : m_children ) {
if ( child - > m_box . computed_values ( ) . z_index ( ) . has_value ( ) & & child - > m_box . computed_values ( ) . z_index ( ) . value ( ) < 0 )
child - > paint ( context ) ;
2020-06-15 17:29:35 +02:00
}
2021-05-07 19:03:25 +03:00
// Draw the background and borders for block-level children (step 4)
paint_descendants ( context , m_box , StackingContextPaintPhase : : BackgroundAndBorders ) ;
// Draw the non-positioned floats (step 5)
paint_descendants ( context , m_box , StackingContextPaintPhase : : Floats ) ;
// Draw inline content, replaced content, etc. (steps 6, 7)
2022-02-14 16:39:45 +01:00
paint_descendants ( context , m_box , StackingContextPaintPhase : : BackgroundAndBordersForInlineLevelAndReplaced ) ;
2022-03-10 14:02:25 +01:00
paint_node ( m_box , context , PaintPhase : : Foreground ) ;
2021-05-07 19:03:25 +03:00
paint_descendants ( context , m_box , StackingContextPaintPhase : : Foreground ) ;
// Draw other positioned descendants (steps 8, 9)
2020-06-15 17:29:35 +02:00
for ( auto * child : m_children ) {
2021-05-07 19:03:25 +03:00
if ( child - > m_box . computed_values ( ) . z_index ( ) . has_value ( ) & & child - > m_box . computed_values ( ) . z_index ( ) . value ( ) < 0 )
continue ;
child - > paint ( context ) ;
2020-06-15 17:29:35 +02:00
}
2021-05-07 19:03:25 +03:00
2022-03-10 14:02:25 +01:00
paint_node ( m_box , context , PaintPhase : : FocusOutline ) ;
paint_node ( m_box , context , PaintPhase : : Overlay ) ;
2021-05-07 19:03:25 +03:00
paint_descendants ( context , m_box , StackingContextPaintPhase : : FocusAndOverlay ) ;
2020-06-15 17:29:35 +02:00
}
2022-03-18 01:29:20 +01:00
Gfx : : FloatMatrix4x4 StackingContext : : get_transformation_matrix ( CSS : : Transformation const & transformation ) const
{
2022-03-21 23:18:38 +01:00
auto count = transformation . values . size ( ) ;
auto value = [ this , transformation ] ( size_t index , CSS : : Length & reference ) - > float {
return transformation . values [ index ] . visit (
[ this , reference ] ( CSS : : LengthPercentage const & value ) {
return value . resolved ( m_box , reference ) . to_px ( m_box ) ;
2022-03-18 01:29:20 +01:00
} ,
2022-03-21 23:18:38 +01:00
[ ] ( float value ) {
return value ;
2022-03-18 01:29:20 +01:00
} ) ;
2022-03-21 23:18:38 +01:00
} ;
2022-04-08 15:56:18 +02:00
auto reference_box = paintable ( ) . absolute_rect ( ) ;
2022-03-21 23:18:38 +01:00
auto width = CSS : : Length : : make_px ( reference_box . width ( ) ) ;
auto height = CSS : : Length : : make_px ( reference_box . height ( ) ) ;
2022-03-18 01:29:20 +01:00
switch ( transformation . function ) {
case CSS : : TransformFunction : : Matrix :
2022-03-21 23:18:38 +01:00
if ( count = = 6 )
return Gfx : : FloatMatrix4x4 ( value ( 0 , width ) , value ( 2 , width ) , 0 , value ( 4 , width ) ,
value ( 1 , height ) , value ( 3 , height ) , 0 , value ( 5 , height ) ,
2022-03-18 01:29:20 +01:00
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
case CSS : : TransformFunction : : Translate :
2022-03-21 23:18:38 +01:00
if ( count = = 1 )
return Gfx : : FloatMatrix4x4 ( 1 , 0 , 0 , value ( 0 , width ) ,
2022-03-18 01:29:20 +01:00
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
2022-03-21 23:18:38 +01:00
if ( count = = 2 )
return Gfx : : FloatMatrix4x4 ( 1 , 0 , 0 , value ( 0 , width ) ,
0 , 1 , 0 , value ( 1 , height ) ,
2022-03-18 01:29:20 +01:00
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
case CSS : : TransformFunction : : TranslateX :
2022-03-21 23:18:38 +01:00
if ( count = = 1 )
return Gfx : : FloatMatrix4x4 ( 1 , 0 , 0 , value ( 0 , width ) ,
2022-03-18 01:29:20 +01:00
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
case CSS : : TransformFunction : : TranslateY :
2022-03-21 23:18:38 +01:00
if ( count = = 1 )
2022-03-18 01:29:20 +01:00
return Gfx : : FloatMatrix4x4 ( 1 , 0 , 0 , 0 ,
2022-03-21 23:18:38 +01:00
0 , 1 , 0 , value ( 0 , height ) ,
2022-03-18 01:29:20 +01:00
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
case CSS : : TransformFunction : : Scale :
2022-03-21 23:18:38 +01:00
if ( count = = 1 )
return Gfx : : FloatMatrix4x4 ( value ( 0 , width ) , 0 , 0 , 0 ,
0 , value ( 0 , height ) , 0 , 0 ,
2022-03-18 01:29:20 +01:00
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
2022-03-21 23:18:38 +01:00
if ( count = = 2 )
return Gfx : : FloatMatrix4x4 ( value ( 0 , width ) , 0 , 0 , 0 ,
0 , value ( 0 , height ) , 0 , 0 ,
2022-03-18 01:29:20 +01:00
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
case CSS : : TransformFunction : : ScaleX :
2022-03-21 23:18:38 +01:00
if ( count = = 1 )
return Gfx : : FloatMatrix4x4 ( value ( 0 , width ) , 0 , 0 , 0 ,
2022-03-18 01:29:20 +01:00
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
case CSS : : TransformFunction : : ScaleY :
2022-03-21 23:18:38 +01:00
if ( count = = 1 )
2022-03-18 01:29:20 +01:00
return Gfx : : FloatMatrix4x4 ( 1 , 0 , 0 , 0 ,
2022-03-21 23:18:38 +01:00
0 , value ( 0 , height ) , 0 , 0 ,
2022-03-18 01:29:20 +01:00
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ) ;
break ;
default :
dbgln_if ( LIBWEB_CSS_DEBUG , " FIXME: Unhandled transformation function {} " , CSS : : TransformationStyleValue : : create ( transformation . function , { } ) - > to_string ( ) ) ;
}
return Gfx : : FloatMatrix4x4 : : identity ( ) ;
}
Gfx : : FloatMatrix4x4 StackingContext : : combine_transformations ( Vector < CSS : : Transformation > const & transformations ) const
{
auto matrix = Gfx : : FloatMatrix4x4 : : identity ( ) ;
for ( auto const & transform : transformations )
matrix = matrix * get_transformation_matrix ( transform ) ;
return matrix ;
}
// FIXME: This extracts the affine 2D part of the full transformation matrix.
// Use the whole matrix when we get better transformation support in LibGfx or use LibGL for drawing the bitmap
Gfx : : AffineTransform StackingContext : : combine_transformations_2d ( Vector < CSS : : Transformation > const & transformations ) const
{
auto matrix = combine_transformations ( transformations ) ;
auto * m = matrix . elements ( ) ;
return Gfx : : AffineTransform ( m [ 0 ] [ 0 ] , m [ 1 ] [ 0 ] , m [ 0 ] [ 1 ] , m [ 1 ] [ 1 ] , m [ 0 ] [ 3 ] , m [ 1 ] [ 3 ] ) ;
}
2022-03-10 15:44:43 +01:00
void StackingContext : : paint ( PaintContext & context ) const
2021-07-23 13:19:16 +03:00
{
2021-10-14 23:49:15 +02:00
Gfx : : PainterStateSaver saver ( context . painter ( ) ) ;
if ( m_box . is_fixed_position ( ) ) {
context . painter ( ) . translate ( context . scroll_offset ( ) ) ;
}
2021-07-23 13:19:16 +03:00
auto opacity = m_box . computed_values ( ) . opacity ( ) ;
2021-10-19 15:27:40 +02:00
if ( opacity = = 0.0f )
2021-07-23 13:19:16 +03:00
return ;
2022-03-18 01:29:20 +01:00
auto affine_transform = combine_transformations_2d ( m_box . computed_values ( ) . transformations ( ) ) ;
if ( opacity < 1.0f | | ! affine_transform . is_identity ( ) ) {
2021-11-06 19:30:59 +01:00
auto bitmap_or_error = Gfx : : Bitmap : : try_create ( Gfx : : BitmapFormat : : BGRA8888 , context . painter ( ) . target ( ) - > size ( ) ) ;
if ( bitmap_or_error . is_error ( ) )
2021-07-23 13:19:16 +03:00
return ;
2021-11-06 19:30:59 +01:00
auto bitmap = bitmap_or_error . release_value_but_fixme_should_propagate_errors ( ) ;
Gfx : : Painter painter ( bitmap ) ;
2022-04-08 19:42:57 +02:00
auto paint_context = context . clone ( painter ) ;
2021-07-23 13:19:16 +03:00
paint_internal ( paint_context ) ;
2022-03-18 01:29:20 +01:00
2022-03-21 19:38:00 +01:00
auto transform_origin = this - > transform_origin ( ) ;
2022-04-08 15:56:18 +02:00
auto source_rect = paintable ( ) . absolute_border_box_rect ( ) . translated ( - transform_origin ) ;
2022-03-20 13:29:01 +01:00
2022-03-18 01:29:20 +01:00
auto transformed_destination_rect = affine_transform . map ( source_rect ) . translated ( transform_origin ) ;
source_rect . translate_by ( transform_origin ) ;
2022-03-23 09:19:13 +01:00
context . painter ( ) . draw_scaled_bitmap ( transformed_destination_rect . to_rounded < int > ( ) , * bitmap , source_rect , opacity , Gfx : : Painter : : ScalingMode : : BilinearBlend ) ;
2021-07-23 13:19:16 +03:00
} else {
paint_internal ( context ) ;
}
}
2022-03-21 19:38:00 +01:00
Gfx : : FloatPoint StackingContext : : transform_origin ( ) const
{
auto style_value = m_box . computed_values ( ) . transform_origin ( ) ;
// FIXME: respect transform-box property
2022-04-08 15:56:18 +02:00
auto reference_box = paintable ( ) . absolute_border_box_rect ( ) ;
2022-03-21 19:38:00 +01:00
auto x = reference_box . left ( ) + style_value . x . resolved ( m_box , CSS : : Length : : make_px ( reference_box . width ( ) ) ) . to_px ( m_box ) ;
auto y = reference_box . top ( ) + style_value . y . resolved ( m_box , CSS : : Length : : make_px ( reference_box . height ( ) ) ) . to_px ( m_box ) ;
return { x , y } ;
}
2022-03-21 11:11:05 +01:00
Optional < HitTestResult > StackingContext : : hit_test ( Gfx : : FloatPoint const & position , HitTestType type ) const
2020-07-01 19:02:28 +02:00
{
2022-03-21 19:38:00 +01:00
auto transform_origin = this - > transform_origin ( ) ;
2022-03-18 01:32:50 +01:00
auto affine_transform = combine_transformations_2d ( m_box . computed_values ( ) . transformations ( ) ) ;
auto transformed_position = affine_transform . inverse ( ) . value_or ( { } ) . map ( position - transform_origin ) + transform_origin ;
2022-03-04 15:02:16 +01:00
// NOTE: Hit testing basically happens in reverse painting order.
// https://www.w3.org/TR/CSS22/visuren.html#z-index
// 7. the child stacking contexts with positive stack levels (least positive first).
for ( ssize_t i = m_children . size ( ) - 1 ; i > = 0 ; - - i ) {
auto const & child = * m_children [ i ] ;
2022-03-21 15:43:37 +01:00
if ( ! child . m_box . is_visible ( ) )
continue ;
2022-03-04 15:02:16 +01:00
if ( child . m_box . computed_values ( ) . z_index ( ) . value_or ( 0 ) < 0 )
2022-03-21 15:43:37 +01:00
continue ;
2022-03-18 01:32:50 +01:00
auto result = child . hit_test ( transformed_position , type ) ;
2022-03-21 11:11:05 +01:00
if ( result . has_value ( ) )
2022-03-04 15:02:16 +01:00
return result ;
}
2022-03-21 11:11:05 +01:00
Optional < HitTestResult > result ;
2022-03-04 15:02:16 +01:00
// 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
2022-04-08 15:56:18 +02:00
paintable ( ) . for_each_in_subtree_of_type < PaintableBox > ( [ & ] ( auto & paint_box ) {
auto & layout_box = paint_box . layout_box ( ) ;
if ( layout_box . is_positioned ( ) & & ! paint_box . stacking_context ( ) ) {
if ( auto candidate = paint_box . hit_test ( transformed_position , type ) ; candidate . has_value ( ) )
2022-03-21 12:12:50 +01:00
result = move ( candidate ) ;
2022-03-04 15:02:16 +01:00
}
return IterationDecision : : Continue ;
} ) ;
2022-03-21 11:11:05 +01:00
if ( result . has_value ( ) )
2022-03-04 15:02:16 +01:00
return result ;
// 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
2022-03-10 02:13:28 +01:00
if ( m_box . children_are_inline ( ) & & is < Layout : : BlockContainer > ( m_box ) ) {
2022-04-08 15:56:18 +02:00
auto result = paintable ( ) . hit_test ( transformed_position , type ) ;
2022-03-21 11:11:05 +01:00
if ( result . has_value ( ) )
2022-03-04 15:02:16 +01:00
return result ;
2020-07-01 19:02:28 +02:00
}
2022-03-04 15:02:16 +01:00
// 4. the non-positioned floats.
2022-04-08 15:56:18 +02:00
paintable ( ) . for_each_in_subtree_of_type < PaintableBox > ( [ & ] ( auto const & paint_box ) {
auto & layout_box = paint_box . layout_box ( ) ;
if ( layout_box . is_floating ( ) ) {
if ( auto candidate = paint_box . hit_test ( transformed_position , type ) ; candidate . has_value ( ) )
2022-03-21 12:12:50 +01:00
result = move ( candidate ) ;
2022-03-04 15:02:16 +01:00
}
return IterationDecision : : Continue ;
} ) ;
2022-03-21 11:11:05 +01:00
if ( result . has_value ( ) )
return result ;
2022-03-04 15:02:16 +01:00
// 3. the in-flow, non-inline-level, non-positioned descendants.
if ( ! m_box . children_are_inline ( ) ) {
2022-04-08 15:56:18 +02:00
paintable ( ) . for_each_in_subtree_of_type < PaintableBox > ( [ & ] ( auto const & paint_box ) {
auto & layout_box = paint_box . layout_box ( ) ;
if ( ! layout_box . is_absolutely_positioned ( ) & & ! layout_box . is_floating ( ) ) {
if ( auto candidate = paint_box . hit_test ( transformed_position , type ) ; candidate . has_value ( ) )
2022-03-21 12:12:50 +01:00
result = move ( candidate ) ;
2022-03-04 15:02:16 +01:00
}
return IterationDecision : : Continue ;
} ) ;
2022-03-21 11:11:05 +01:00
if ( result . has_value ( ) )
2022-03-04 15:02:16 +01:00
return result ;
}
2021-03-31 10:26:11 -04:00
2022-03-04 15:02:16 +01:00
// 2. the child stacking contexts with negative stack levels (most negative first).
for ( ssize_t i = m_children . size ( ) - 1 ; i > = 0 ; - - i ) {
auto const & child = * m_children [ i ] ;
if ( child . m_box . computed_values ( ) . z_index ( ) . value_or ( 0 ) < 0 )
2022-03-21 15:43:37 +01:00
continue ;
if ( ! child . m_box . is_visible ( ) )
continue ;
2022-03-18 01:32:50 +01:00
auto result = child . hit_test ( transformed_position , type ) ;
2022-03-21 11:11:05 +01:00
if ( result . has_value ( ) )
2022-03-04 15:02:16 +01:00
return result ;
}
2021-03-31 10:26:11 -04:00
2022-03-04 15:02:16 +01:00
// 1. the background and borders of the element forming the stacking context.
2022-04-08 15:56:18 +02:00
if ( paintable ( ) . absolute_border_box_rect ( ) . contains ( transformed_position ) ) {
2022-03-11 00:03:28 +01:00
return HitTestResult {
2022-04-08 15:56:18 +02:00
. paintable = paintable ( ) ,
2022-03-04 15:02:16 +01:00
} ;
2020-07-01 19:02:28 +02:00
}
2022-03-04 15:02:16 +01:00
return { } ;
2020-07-01 19:02:28 +02:00
}
2020-06-15 17:29:35 +02:00
void StackingContext : : dump ( int indent ) const
{
2021-01-01 16:42:44 +01:00
StringBuilder builder ;
2020-06-15 17:29:35 +02:00
for ( int i = 0 ; i < indent ; + + i )
2021-01-01 16:42:44 +01:00
builder . append ( ' ' ) ;
2022-04-08 15:56:18 +02:00
builder . appendff ( " SC for {} {} [children: {}] (z-index: " , m_box . debug_description ( ) , paintable ( ) . absolute_rect ( ) , m_children . size ( ) ) ;
2022-03-04 15:03:48 +01:00
if ( m_box . computed_values ( ) . z_index ( ) . has_value ( ) )
builder . appendff ( " {} " , m_box . computed_values ( ) . z_index ( ) . value ( ) ) ;
else
builder . append ( " auto " ) ;
builder . append ( ' ) ' ) ;
2022-03-18 01:29:20 +01:00
auto affine_transform = combine_transformations_2d ( m_box . computed_values ( ) . transformations ( ) ) ;
if ( ! affine_transform . is_identity ( ) ) {
builder . appendff ( " , transform: {} " , affine_transform ) ;
}
2021-01-01 16:42:44 +01:00
dbgln ( " {} " , builder . string_view ( ) ) ;
2020-06-15 17:29:35 +02:00
for ( auto & child : m_children )
child - > dump ( indent + 1 ) ;
}
}