LibWeb: Skip repaint for visual context-only style changes
Let style changes that only rebuild compatible accumulated visual contexts avoid marking the display list dirty. This lets transform and nonzero opacity updates send visual context tree updates without recording a new display list. Keep repainting changes that affect display-list contents or can change visual context tree compatibility, including zero-crossing opacity, transform invertibility crossings, background-attachment, clipping, mix-blend-mode, and perspective. Schedule accumulated visual context updates for animations independently of repaint so animated transform/effect updates keep reaching the document. Cover compatible visual context reuse, incompatible tree shapes, and the display-list invalidation cases with focused LibWeb tests.
This commit is contained in:
parent
1b8072371b
commit
b583fd3b79
18 changed files with 521 additions and 5 deletions
|
|
@ -873,10 +873,10 @@ AnimationUpdateContext::~AnimationUpdateContext()
|
|||
target->set_needs_layout_tree_update(true, DOM::SetNeedsLayoutTreeUpdateReason::KeyframeEffect);
|
||||
}
|
||||
}
|
||||
if (invalidation.repaint) {
|
||||
if (invalidation.rebuild_accumulated_visual_contexts)
|
||||
element.document().set_needs_accumulated_visual_contexts_update(true);
|
||||
if (invalidation.rebuild_accumulated_visual_contexts)
|
||||
element.document().set_needs_accumulated_visual_contexts_update(true);
|
||||
|
||||
if (invalidation.repaint) {
|
||||
target->set_needs_repaint();
|
||||
}
|
||||
if (invalidation.rebuild_stacking_context_tree)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/OpacityValueStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
|
||||
#include <LibWeb/CSS/StyleValues/TransformationStyleValue.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
|
|
@ -59,6 +60,81 @@ static bool is_stacking_context_creating_value(CSS::PropertyID property_id, Styl
|
|||
}
|
||||
}
|
||||
|
||||
static bool opacity_change_affects_paintable_visibility(CSS::PropertyID property_id, StyleValue const* old_value, StyleValue const* new_value)
|
||||
{
|
||||
if (property_id != CSS::PropertyID::Opacity)
|
||||
return false;
|
||||
|
||||
auto old_opacity = old_value ? old_value->as_opacity_value().resolved() : 1.0f;
|
||||
auto new_opacity = new_value ? new_value->as_opacity_value().resolved() : 1.0f;
|
||||
return (old_opacity == 0.0f) != (new_opacity == 0.0f);
|
||||
}
|
||||
|
||||
static Optional<bool> transform_value_is_invertible(StyleValue const* value)
|
||||
{
|
||||
if (!value || value->to_keyword() == CSS::Keyword::None)
|
||||
return true;
|
||||
|
||||
auto transformation_is_invertible = [](TransformationStyleValue const& transformation) -> Optional<bool> {
|
||||
if (!transformation.can_be_converted_to_matrix_without_reference_box())
|
||||
return {};
|
||||
return transformation.to_matrix({}).is_invertible();
|
||||
};
|
||||
|
||||
if (value->is_transformation())
|
||||
return transformation_is_invertible(value->as_transformation());
|
||||
|
||||
if (value->is_value_list()) {
|
||||
auto matrix = Gfx::FloatMatrix4x4::identity();
|
||||
for (auto const& transformation : value->as_value_list().values()) {
|
||||
if (!transformation->is_transformation())
|
||||
return {};
|
||||
if (!transformation->as_transformation().can_be_converted_to_matrix_without_reference_box())
|
||||
return {};
|
||||
matrix = matrix * transformation->as_transformation().to_matrix({});
|
||||
}
|
||||
return matrix.is_invertible();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool transform_change_requires_repaint(CSS::PropertyID property_id, StyleValue const* old_value, StyleValue const* new_value)
|
||||
{
|
||||
if (!AK::first_is_one_of(property_id, CSS::PropertyID::Transform, CSS::PropertyID::Scale))
|
||||
return false;
|
||||
|
||||
// StackingContext::paint() omits non-invertibly transformed subtrees, so crossing
|
||||
// this boundary changes display-list contents, not just the visual context matrix.
|
||||
auto old_invertible = transform_value_is_invertible(old_value);
|
||||
auto new_invertible = transform_value_is_invertible(new_value);
|
||||
if (!old_invertible.has_value() || !new_invertible.has_value())
|
||||
return true;
|
||||
return old_invertible.value() != new_invertible.value();
|
||||
}
|
||||
|
||||
static bool accumulated_visual_context_change_requires_repaint(CSS::PropertyID property_id, StyleValue const* old_value, StyleValue const* new_value)
|
||||
{
|
||||
if (opacity_change_affects_paintable_visibility(property_id, old_value, new_value))
|
||||
return true;
|
||||
|
||||
if (transform_change_requires_repaint(property_id, old_value, new_value))
|
||||
return true;
|
||||
|
||||
switch (property_id) {
|
||||
case CSS::PropertyID::BackgroundAttachment:
|
||||
case CSS::PropertyID::Clip:
|
||||
case CSS::PropertyID::ClipPath:
|
||||
case CSS::PropertyID::MixBlendMode:
|
||||
case CSS::PropertyID::Perspective:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RequiredInvalidationAfterStyleChange compute_property_invalidation(CSS::PropertyID property_id, StyleValue const* old_value, StyleValue const* new_value)
|
||||
{
|
||||
RequiredInvalidationAfterStyleChange invalidation;
|
||||
|
|
@ -135,8 +211,16 @@ RequiredInvalidationAfterStyleChange compute_property_invalidation(CSS::Property
|
|||
}
|
||||
invalidation.repaint = true;
|
||||
|
||||
if (CSS::property_affects_accumulated_visual_contexts(property_id))
|
||||
if (CSS::property_affects_accumulated_visual_contexts(property_id)) {
|
||||
invalidation.rebuild_accumulated_visual_contexts = true;
|
||||
if (!accumulated_visual_context_change_requires_repaint(property_id, old_value, new_value)
|
||||
&& !invalidation.rebuild_stacking_context_tree
|
||||
&& !invalidation.relayout
|
||||
&& !invalidation.rebuild_layout_tree
|
||||
&& !invalidation.recompute_descendant_styles
|
||||
&& !invalidation.inherited_style_changed)
|
||||
invalidation.repaint = false;
|
||||
}
|
||||
|
||||
return invalidation;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2041,7 +2041,10 @@ static void apply_element_style_invalidation_after_style_change(Element& element
|
|||
|
||||
static void apply_document_style_invalidation_after_style_change(Document& document, CSS::RequiredInvalidationAfterStyleChange const& invalidation)
|
||||
{
|
||||
if (!invalidation.is_none())
|
||||
if (invalidation.repaint
|
||||
|| invalidation.rebuild_stacking_context_tree
|
||||
|| invalidation.relayout
|
||||
|| invalidation.rebuild_layout_tree)
|
||||
document.set_needs_to_record_display_list();
|
||||
if (invalidation.rebuild_accumulated_visual_contexts)
|
||||
document.set_needs_accumulated_visual_contexts_update(true);
|
||||
|
|
|
|||
|
|
@ -54,3 +54,31 @@ TEST_CASE(compatibility_requires_same_shape)
|
|||
|
||||
EXPECT(!different_parent_tree.is_compatible_with(same_node_count_tree));
|
||||
}
|
||||
|
||||
TEST_CASE(compatibility_requires_same_empty_effective_clip)
|
||||
{
|
||||
auto empty_clip_tree = AccumulatedVisualContextTree::create();
|
||||
empty_clip_tree.append(ClipData { Web::DevicePixelRect {}, {} }, VISUAL_VIEWPORT_NODE_INDEX);
|
||||
|
||||
auto non_empty_clip_tree = AccumulatedVisualContextTree::create();
|
||||
non_empty_clip_tree.append(ClipData { Web::DevicePixelRect { 0, 0, 1, 1 }, {} }, VISUAL_VIEWPORT_NODE_INDEX);
|
||||
|
||||
EXPECT(!empty_clip_tree.is_compatible_with(non_empty_clip_tree));
|
||||
}
|
||||
|
||||
TEST_CASE(compatibility_requires_same_visual_context_types)
|
||||
{
|
||||
auto clip_tree = AccumulatedVisualContextTree::create();
|
||||
clip_tree.append(ClipData { Web::DevicePixelRect { 0, 0, 1, 1 }, {} }, VISUAL_VIEWPORT_NODE_INDEX);
|
||||
|
||||
Gfx::Path path;
|
||||
path.move_to({ 0, 0 });
|
||||
path.line_to({ 1, 0 });
|
||||
path.line_to({ 1, 1 });
|
||||
path.close();
|
||||
|
||||
auto clip_path_tree = AccumulatedVisualContextTree::create();
|
||||
clip_path_tree.append(ClipPathData { path, Web::DevicePixelRect { 0, 0, 1, 1 }, Gfx::WindingRule::Nonzero }, VISUAL_VIEWPORT_NODE_INDEX);
|
||||
|
||||
EXPECT(!clip_tree.is_compatible_with(clip_path_tree));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
Before animation update:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] transform=[1,0,0,1,10,0] origin=(58,58) (PaintableWithLines(BlockContainer<DIV>#box))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@2 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
After animation update:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] transform=[1,0,0,1,15,0] origin=(58,58) (PaintableWithLines(BlockContainer<DIV>#box))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@2 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
Before background-attachment change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x213]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x200]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 200x200]
|
||||
Save@1
|
||||
AddClipRect@1 rect=[0,0 200x200]
|
||||
PaintLinearGradient@1 rect=[0,0 200x600]
|
||||
Restore@1
|
||||
Restore@0
|
||||
|
||||
After background-attachment change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] scroll_compensation(frame_id=1)
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x213]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x200]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 200x200]
|
||||
Save@1
|
||||
AddClipRect@1 rect=[0,0 200x200]
|
||||
PaintLinearGradient@2 rect=[0,0 800x600]
|
||||
Restore@1
|
||||
Restore@0
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
Before clip change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x21]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,13 100x100]
|
||||
FillRect@1 rect=[8,13 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
After clip change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] clip=[8,13 50x50] (PaintableWithLines(BlockContainer<DIV>#box))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x21]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,13 100x100]
|
||||
FillRect@2 rect=[8,13 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
Before clip-path change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] clip_path=[bounds: 8,8 100x100, path: M8 8L108 8L108 108L8 108L8 8Z] (PaintableWithLines(BlockContainer<DIV>#box))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@2 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
After clip-path change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
Restore@0
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
Before mix-blend-mode change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@1 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
After mix-blend-mode change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] effects=[blend_mode=2] (PaintableWithLines(BlockContainer<DIV>#box))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@2 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
Before perspective change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] transform=[1,0,0,1,0,0] origin=(58,58) (PaintableWithLines(BlockContainer<DIV>#child))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@2 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
After perspective change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] perspective
|
||||
[3] transform=[1,0,0,1,0,0] origin=(58,58) (PaintableWithLines(BlockContainer<DIV>#child))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
CompositorWheelHitTestTarget@3 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@3 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
Before transform change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
Restore@0
|
||||
|
||||
After transform change:
|
||||
AccumulatedVisualContext Tree:
|
||||
[0] transform=[1,0,0,1,0,0] origin=(0,0) (ViewportPaintable(Viewport<#document>))
|
||||
[1] scroll_frame_id=1 (PaintableWithLines(BlockContainer<PRE>#out))
|
||||
[2] transform=[1,0,0,1,0,0] origin=(58,58) (PaintableWithLines(BlockContainer<DIV>#box))
|
||||
|
||||
DisplayList:
|
||||
SaveLayer@0
|
||||
CompositorWheelHitTestTarget@0 target_scroll_frame_index=0 rect=[0,0 800x600]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[0,0 800x121]
|
||||
CompositorWheelHitTestTarget@1 target_scroll_frame_index=0 rect=[8,8 784x100]
|
||||
CompositorWheelHitTestTarget@2 target_scroll_frame_index=0 rect=[8,8 100x100]
|
||||
FillRect@2 rect=[8,8 100x100] color=rgb(0, 128, 0)
|
||||
Restore@0
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
<div id="box"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const animation = box.animate([
|
||||
{ transform: "translateX(10px)" },
|
||||
{ transform: "translateX(20px)" },
|
||||
], 1000);
|
||||
animation.pause();
|
||||
|
||||
animation.currentTime = 0;
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
animation.currentTime = 500;
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before animation update:");
|
||||
println(displayListBefore);
|
||||
println("After animation update:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#box {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-image: linear-gradient(green, blue);
|
||||
background-size: 100% 100vh;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: scroll;
|
||||
}
|
||||
</style>
|
||||
<div id="box"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
box.style.backgroundAttachment = "fixed";
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before background-attachment change:");
|
||||
println(displayListBefore);
|
||||
println("After background-attachment change:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#box {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
clip: auto;
|
||||
}
|
||||
</style>
|
||||
<div id="box"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
box.style.clip = "rect(0, 50px, 50px, 0)";
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before clip change:");
|
||||
println(displayListBefore);
|
||||
println("After clip change:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
clip-path: inset(0);
|
||||
}
|
||||
</style>
|
||||
<div id="box"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
box.style.clipPath = "inset(50%)";
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before clip-path change:");
|
||||
println(displayListBefore);
|
||||
println("After clip-path change:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
mix-blend-mode: normal;
|
||||
}
|
||||
</style>
|
||||
<div id="box"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
box.style.mixBlendMode = "multiply";
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before mix-blend-mode change:");
|
||||
println(displayListBefore);
|
||||
println("After mix-blend-mode change:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
perspective: none;
|
||||
}
|
||||
|
||||
#child {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
transform: translateZ(10px);
|
||||
}
|
||||
</style>
|
||||
<div id="box"><div id="child"></div></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
box.style.perspective = "100px";
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before perspective change:");
|
||||
println(displayListBefore);
|
||||
println("After perspective change:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<!doctype html>
|
||||
<script src="../include.js"></script>
|
||||
<style>
|
||||
#box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: green;
|
||||
transform: scale(0);
|
||||
}
|
||||
</style>
|
||||
<div id="box"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
const box = document.getElementById("box");
|
||||
const displayListBefore = internals.dumpDisplayList();
|
||||
|
||||
box.style.transform = "scale(1)";
|
||||
const displayListAfter = internals.dumpDisplayList();
|
||||
|
||||
println("Before transform change:");
|
||||
println(displayListBefore);
|
||||
println("After transform change:");
|
||||
println(displayListAfter);
|
||||
});
|
||||
</script>
|
||||
Loading…
Reference in a new issue