summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/paint
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-16 11:45:35 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-17 08:59:23 +0000
commit552906b0f222c5d5dd11b9fd73829d510980461a (patch)
tree3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/third_party/blink/renderer/core/paint
parent1b05827804eaf047779b597718c03e7d38344261 (diff)
downloadqtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/paint')
-rw-r--r--chromium/third_party/blink/renderer/core/paint/BUILD.gn2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/DEPS7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/README.md66
-rw-r--r--chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc101
-rw-r--r--chromium/third_party/blink/renderer/core/paint/background_image_geometry.h11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/block_painter_test.cc260
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_border_painter.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_model_object_painter.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc75
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc113
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter.h12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_base.cc153
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_base.h24
-rw-r--r--chromium/third_party/blink/renderer/core/paint/box_painter_test.cc148
-rw-r--r--chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/paint/clip_path_clipper.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc270
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h34
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc201
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc124
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc324
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc90
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/paint/fragment_data.h17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/frame_paint_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/frame_painter.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing.cc65
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing.h15
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc183
-rw-r--r--chromium/third_party/blink/renderer/core/paint/image_painter.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/line_box_list_painter.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc50
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/multi_column_set_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/README.md19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc1377
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h233
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h1
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc84
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h45
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h33
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc265
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_painter.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/object_painter_base.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc159
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc300
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_info.h12
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc187
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_invalidator.h9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer.cc243
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer.h49
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_fragment.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc231
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc570
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc600
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h105
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc283
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc71
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_phase.h4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc561
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h26
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc450
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc138
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing.h13
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h45
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc219
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h10
-rw-r--r--chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/paint/replaced_painter.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h16
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc106
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h31
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.h8
-rw-r--r--chromium/third_party/blink/renderer/core/paint/selection_painting_utils.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_container_painter.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_filter_painter.cc160
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_filter_painter.h27
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_foreign_object_painter.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc52
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_inline_flow_box_painter.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_mask_painter.h15
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.h18
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_root_painter.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_shape_painter.h3
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_text_painter.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/paint/svg_text_painter.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_painter_test.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_row_painter.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_row_painter.h5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/table_section_painter.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_element_timing.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_element_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_style.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/paint/text_painter_base.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/paint/theme_painter.cc169
-rw-r--r--chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/paint/video_painter.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/paint/video_painter_test.cc82
-rw-r--r--chromium/third_party/blink/renderer/core/paint/view_painter.cc270
-rw-r--r--chromium/third_party/blink/renderer/core/paint/view_painter.h17
-rw-r--r--chromium/third_party/blink/renderer/core/paint/view_painter_test.cc230
176 files changed, 7115 insertions, 4786 deletions
diff --git a/chromium/third_party/blink/renderer/core/paint/BUILD.gn b/chromium/third_party/blink/renderer/core/paint/BUILD.gn
index 335341d4569..98c25ea6a92 100644
--- a/chromium/third_party/blink/renderer/core/paint/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/paint/BUILD.gn
@@ -134,6 +134,8 @@ blink_core_sources("paint") {
"ng/ng_fragment_painter.h",
"ng/ng_inline_box_fragment_painter.cc",
"ng/ng_inline_box_fragment_painter.h",
+ "ng/ng_mathml_painter.cc",
+ "ng/ng_mathml_painter.h",
"ng/ng_paint_fragment.cc",
"ng/ng_paint_fragment.h",
"ng/ng_paint_fragment_traversal.cc",
diff --git a/chromium/third_party/blink/renderer/core/paint/DEPS b/chromium/third_party/blink/renderer/core/paint/DEPS
index 25664f0f1f8..75b3e64e39c 100644
--- a/chromium/third_party/blink/renderer/core/paint/DEPS
+++ b/chromium/third_party/blink/renderer/core/paint/DEPS
@@ -7,11 +7,14 @@ include_rules = [
]
specific_include_rules = {
- "(theme_painter|fallback_theme)\.cc": [
+ "(theme_painter|fallback_theme|object_painter_base)\.cc": [
"+ui/native_theme/native_theme.h",
"+ui/native_theme/native_theme_base.h",
],
".*test\.cc": [
"+base/test/trace_event_analyzer.h",
- ]
+ ],
+ "video_painter_test.cc": [
+ "+components/paint_preview/common/paint_preview_tracker.h",
+ ],
}
diff --git a/chromium/third_party/blink/renderer/core/paint/README.md b/chromium/third_party/blink/renderer/core/paint/README.md
index 7dd05de5f52..6d5696496b2 100644
--- a/chromium/third_party/blink/renderer/core/paint/README.md
+++ b/chromium/third_party/blink/renderer/core/paint/README.md
@@ -165,12 +165,11 @@ most recent step towards CompositeAfterPaint was a project called
which uses the compositing decisions from the current compositor
(PaintLayerCompositor, which produces GraphicsLayers) with the new
CompositeAfterPaint compositor (PaintArtifactCompositor). This is done by a step
-at the end of paint which collects all painted GraphicsLayers (and their
-associated cc::Layers) as a list of
-[ForeignLayerDisplayItem](../../platform/graphics/paint/foreign_layer_display_item.h)s.
-Foreign layers are typically used for cc::Layers managed outside blink (e.g.,
+at the end of paint which collects all painted GraphicsLayers as a list of
+[GraphicsLayerDisplayItem](../../platform/graphics/paint/graphics_layer_display_item.h)s.
+Additionaly, [ForeignLayerDisplayItem](../../platform/graphics/paint/foreign_layer_display_item.h)s are used for cc::Layers managed outside blink (e.g.,
video layers, plugin layers) and are treated as opaque composited content by
-the PaintArtifactCompositor. This approach of using foreign layers starts using
+the PaintArtifactCompositor. This approach starts using
much of the new PaintArtifactCompositor logic (e.g., converting blink property
trees to cc property trees) without changing how compositing decisions are made.
@@ -292,9 +291,9 @@ from layout
|<--------------------------------------------------+
| PaintChunksToCcLayer::Convert() |
v |
-+----------------+ |
-| Foreign layers | |
-+----------------+ |
++--------------------------------------------------+ |
+| GraphicsLayerDisplayItem/ForeignLayerDisplayItem | |
++--------------------------------------------------+ |
| |
| LocalFrameView::PushPaintArtifactToCompositor() |
| PaintArtifactCompositor::Update() |
@@ -647,8 +646,7 @@ a PaintLayer and whether we can use cached subsequence for a PaintLayer. See
During painting, we walk the layout tree multiple times for multiple paint
phases. Sometimes a layer contain nothing needing a certain paint phase and we
can skip tree walk for such empty phases. Now we have optimized
-`PaintPhaseDescendantBlockBackgroundsOnly`, `PaintPhaseDescendantOutlinesOnly`
-and `PaintPhaseFloat` for empty paint phases.
+`PaintPhaseDescendantOutlinesOnly` and `PaintPhaseFloat` for empty paint phases.
During paint invalidation, we set the containing self-painting layer's
`NeedsPaintPhaseXXX` flag if the object has something needing to be painted in
@@ -663,36 +661,40 @@ if an object changes style and creates a self-painting-layer, we copy the flags
from its containing self-painting layer to this layer, assuming that this layer
needs all paint phases that its container self-painting layer needs.
-We could update the `NeedsPaintPhaseXXX` flags in a separate tree walk, but that
-would regress performance of the first paint. For CompositeAfterPaint, we can
-update the flags during the pre-painting tree walk to simplify the logic.
-
-### Hit test painting
+### Hit test information recording
Hit testing is done in paint-order, and to preserve this information the paint
-system is re-used to paint hit test display items in the background phase of
-painting. This information is then used in the compositor to implement cc-side
-hit testing. Hit test display items are produced even if there is no painted
-content.
+system is re-used to record hit test information when painting the background.
+This information is then used in the compositor to implement cc-side hit
+testing. Hit test information is recorded even if there is no painted content.
+
+We record different types of hit test information in the following data
+structures:
+
+1. Paint chunk bounds
-There are two types of hit test painting:
+ The bounds of the current paint chunk are expanded to ensure the bounds
+ contain the hit testable area.
-1. [HitTestDisplayItem](../../platform/graphics/paint/hit_test_display_item.h)
+2. [`HitTestData::touch_action_rects`](../../platform/graphics/paint/hit_test_data.h)
- Used for [touch action rects](http://docs.google.com/document/u/1/d/1ksiqEPkDeDuI_l5HvWlq1MfzFyDxSnsNB8YXIaXa3sE/view)
- which are areas of the page that allow certain gesture effects, as well as
- areas of the page that disallow touch events due to blocking touch event
- handlers.
+ Used for [touch action rects](http://docs.google.com/document/u/1/d/1ksiqEPkDeDuI_l5HvWlq1MfzFyDxSnsNB8YXIaXa3sE/view)
+ which are areas of the page that allow certain gesture effects, as well as
+ areas of the page that disallow touch events due to blocking touch event
+ handlers.
-2. [ScrollHitTestDisplayItem](../../platform/graphics/paint/scroll_hit_test_display_item.h)
+3. [`HitTestData::scroll_translation`](../../platform/graphics/paint/hit_test_data.h)
+ and
+ [`HitTestData::scroll_hit_test_rect`](../../platform/graphics/paint/hit_test_data.h)
- Used to create
- [non-fast scrollable regions](https://docs.google.com/document/d/1IyYJ6bVF7KZq96b_s5NrAzGtVoBXn_LQnya9y4yT3iw/view)
- to prevent compositor scrolling of non-composited scrollers, plugins with
- blocking scroll event handlers, and resize handles.
+ Used to create
+ [non-fast scrollable regions](https://docs.google.com/document/d/1IyYJ6bVF7KZq96b_s5NrAzGtVoBXn_LQnya9y4yT3iw/view)
+ to prevent compositor scrolling of non-composited scrollers, plugins with
+ blocking scroll event handlers, and resize handles.
- This is also used for CompositeAfterPaint to force a special cc::Layer that
- is marked as being scrollable.
+ If `scroll_translation` is not null, this is also used for
+ CompositeAfterPaint to force a special cc::Layer that is marked as being
+ scrollable when composited scrolling is needed for the scroller.
### Scrollbar painting
diff --git a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
index a92ade16bda..eadaebbe0fc 100644
--- a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -39,27 +39,12 @@ inline LayoutUnit GetSpaceBetweenImageTiles(LayoutUnit area_size,
bool FixedBackgroundPaintsInLocalCoordinates(
const LayoutObject& obj,
const GlobalPaintFlags global_paint_flags) {
- if (!obj.IsLayoutView())
+ const auto* view = DynamicTo<LayoutView>(obj);
+ if (!view)
return false;
- const LayoutView& view = ToLayoutView(obj);
-
- // TODO(wangxianzhu): For CAP, inline this function into
- // FixedBackgroundPaintsInLocalCoordinates().
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- return view.GetBackgroundPaintLocation() !=
- kBackgroundPaintInScrollingContents;
- }
-
- if (global_paint_flags & kGlobalPaintFlattenCompositingLayers)
- return false;
-
- PaintLayer* root_layer = view.Layer();
- if (!root_layer || root_layer->GetCompositingState() == kNotComposited)
- return false;
-
- CompositedLayerMapping* mapping = root_layer->GetCompositedLayerMapping();
- return !mapping->BackgroundPaintsOntoScrollingContentsLayer();
+ return !(view->GetBackgroundPaintLocation() &
+ kBackgroundPaintInScrollingContents);
}
LayoutPoint AccumulatedScrollOffsetForFixedBackground(
@@ -103,15 +88,17 @@ void BackgroundImageGeometry::SetNoRepeatX(const FillLayer& fill_layer,
return;
}
- // The snapped offset may not yet be snapped, so make sure it is an integer.
- snapped_x_offset = LayoutUnit(RoundToInt(snapped_x_offset));
-
if (x_offset > 0) {
DCHECK(snapped_x_offset >= LayoutUnit());
// Move the dest rect if the offset is positive. The image "stays" where
// it is over the dest rect, so this effectively modifies the phase.
unsnapped_dest_rect_.Move(x_offset, LayoutUnit());
- snapped_dest_rect_.Move(snapped_x_offset, LayoutUnit());
+
+ // For the snapped geometry, note that negative x_offsets typically
+ // arise when using positive offsets from the bottom of the background
+ // rect. We try to move the snapped dest rect to give the same offset.
+ LayoutUnit dx = snapped_dest_rect_.Width() - unsnapped_dest_rect_.Width();
+ snapped_dest_rect_.Move(x_offset + dx, LayoutUnit());
// Make the dest as wide as a tile, which will reduce the dest
// rect if the tile is too small to fill the paint_rect. If not,
@@ -147,16 +134,17 @@ void BackgroundImageGeometry::SetNoRepeatY(const FillLayer& fill_layer,
LayoutSize(SpaceSize().Width(), unsnapped_dest_rect_.Height()));
return;
}
-
- // The snapped offset may not yet be snapped, so make sure it is an integer.
- snapped_y_offset = LayoutUnit(RoundToInt(snapped_y_offset));
-
if (y_offset > 0) {
DCHECK(snapped_y_offset >= LayoutUnit());
// Move the dest rect if the offset is positive. The image "stays" where
// it is in the paint rect, so this effectively modifies the phase.
unsnapped_dest_rect_.Move(LayoutUnit(), y_offset);
- snapped_dest_rect_.Move(LayoutUnit(), snapped_y_offset);
+
+ // For the snapped geometry, note that negative y_offsets typically
+ // arise when using positive offsets from the bottom of the background
+ // rect. We try to move the snapped dest rect to give the same offset.
+ LayoutUnit dy = snapped_dest_rect_.Height() - unsnapped_dest_rect_.Height();
+ snapped_dest_rect_.Move(LayoutUnit(), y_offset + dy);
// Make the dest as wide as a tile, which will reduce the dest
// rect if the tile is too small to fill the paint_rect. If not,
@@ -402,17 +390,9 @@ LayoutRect FixedAttachmentPositioningArea(const LayoutBoxModelObject& obj,
// The LayoutView is the only object that can paint a fixed background into
// its scrolling contents layer, so it gets a special adjustment here.
- if (obj.IsLayoutView()) {
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- DCHECK_EQ(obj.GetBackgroundPaintLocation(),
- kBackgroundPaintInScrollingContents);
- rect.SetLocation(LayoutPoint(ToLayoutView(obj).ScrolledContentOffset()));
- } else if (auto* mapping = obj.Layer()->GetCompositedLayerMapping()) {
- if (mapping->BackgroundPaintsOntoScrollingContentsLayer()) {
- rect.SetLocation(
- LayoutPoint(ToLayoutView(obj).ScrolledContentOffset()));
- }
- }
+ if (auto* layout_view = DynamicTo<LayoutView>(obj)) {
+ if (obj.GetBackgroundPaintLocation() & kBackgroundPaintInScrollingContents)
+ rect.SetLocation(LayoutPoint(layout_view->ScrolledContentOffset()));
}
rect.MoveBy(AccumulatedScrollOffsetForFixedBackground(obj, container));
@@ -442,13 +422,13 @@ LayoutRect FixedAttachmentPositioningArea(const LayoutBoxModelObject& obj,
} // Anonymous namespace
-BackgroundImageGeometry::BackgroundImageGeometry(const LayoutView& view)
+BackgroundImageGeometry::BackgroundImageGeometry(
+ const LayoutView& view,
+ bool root_elemnet_has_transform)
: box_(view),
positioning_box_(view.RootBox()),
- has_non_local_geometry_(false),
painting_view_(true),
- painting_table_cell_(false),
- cell_using_container_background_(false) {
+ root_element_has_transform_(root_elemnet_has_transform) {
// The background of the box generated by the root element covers the
// entire canvas and will be painted by the view object, but the we should
// still use the root element box for positioning.
@@ -457,14 +437,9 @@ BackgroundImageGeometry::BackgroundImageGeometry(const LayoutView& view)
BackgroundImageGeometry::BackgroundImageGeometry(
const LayoutBoxModelObject& obj)
- : box_(obj),
- positioning_box_(obj),
- has_non_local_geometry_(false),
- painting_view_(false),
- painting_table_cell_(false),
- cell_using_container_background_(false) {
+ : box_(obj), positioning_box_(obj) {
// Specialized constructor should be used for LayoutView.
- DCHECK(!obj.IsLayoutView());
+ DCHECK(!IsA<LayoutView>(obj));
}
BackgroundImageGeometry::BackgroundImageGeometry(
@@ -474,8 +449,6 @@ BackgroundImageGeometry::BackgroundImageGeometry(
positioning_box_(background_object && !background_object->IsTableCell()
? ToLayoutBoxModelObject(*background_object)
: cell),
- has_non_local_geometry_(false),
- painting_view_(false),
painting_table_cell_(true) {
cell_using_container_background_ =
background_object && !background_object->IsTableCell();
@@ -729,11 +702,14 @@ void BackgroundImageGeometry::ComputePositioningArea(
snapped_box_offset =
LayoutPoint(snapped_box_outset.Left() - snapped_dest_adjust.Left(),
snapped_box_outset.Top() - snapped_dest_adjust.Top());
- // For view backgrounds, the input paint rect is specified in root element
- // local coordinate (i.e. a transform is applied on the context for
- // painting), and is expanded to cover the whole canvas. Since left/top is
- // relative to the paint rect, we need to offset them back.
- if (painting_view_) {
+
+ // |paint_rect|'s location is usually assumed by BackgroundImageGeometry
+ // to encode paint offset in the local transform space. The one case in
+ // which this is not true is painting the background of the LayoutView
+ // canvas when the HTML element has a transform. In that case, the
+ // paint offset is zero, and the offset gets applied later by a
+ // PaintOffsetTranslation.
+ if (painting_view_ && root_element_has_transform_) {
unsnapped_box_offset -= paint_rect.Location();
snapped_box_offset -= paint_rect.Location();
}
@@ -756,7 +732,8 @@ void BackgroundImageGeometry::CalculateFillTileSize(
: unsnapped_positioning_area_size;
LayoutSize image_intrinsic_size(image->ImageSize(
positioning_box_.GetDocument(),
- positioning_box_.StyleRef().EffectiveZoom(), positioning_area_size));
+ positioning_box_.StyleRef().EffectiveZoom(), positioning_area_size,
+ LayoutObject::ShouldRespectImageOrientation(&box_)));
switch (type) {
case EFillSizeType::kSizeLength: {
tile_size_ = positioning_area_size;
@@ -1039,9 +1016,13 @@ void BackgroundImageGeometry::Calculate(const LayoutBoxModelObject* container,
if (ShouldUseFixedAttachment(fill_layer))
UseFixedAttachment(paint_rect.Location());
- // Clip the final output rect to the paint rect, maintaining snapping.
+ // Clip the final output rect to the paint rect.
unsnapped_dest_rect_.Intersect(paint_rect);
- snapped_dest_rect_.Intersect(LayoutRect(PixelSnappedIntRect(paint_rect)));
+
+ // Clip the snapped rect, and re-snap the dest rect as we may have
+ // adjusted it with unsnapped values.
+ snapped_dest_rect_.Intersect(paint_rect);
+ snapped_dest_rect_ = LayoutRect(PixelSnappedIntRect(snapped_dest_rect_));
}
const ImageResourceObserver& BackgroundImageGeometry::ImageClient() const {
diff --git a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.h b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.h
index cac45a7592c..02c1f2eb794 100644
--- a/chromium/third_party/blink/renderer/core/paint/background_image_geometry.h
+++ b/chromium/third_party/blink/renderer/core/paint/background_image_geometry.h
@@ -31,7 +31,7 @@ class BackgroundImageGeometry {
public:
// Constructor for LayoutView where the coordinate space is different.
- BackgroundImageGeometry(const LayoutView&);
+ BackgroundImageGeometry(const LayoutView&, bool root_elemnet_has_transform);
// Constructor for table cells where background_object may be the row or
// column the background image is attached to.
@@ -181,10 +181,11 @@ class BackgroundImageGeometry {
FloatPoint phase_;
LayoutSize tile_size_;
LayoutSize repeat_spacing_;
- bool has_non_local_geometry_;
- bool painting_view_;
- bool painting_table_cell_;
- bool cell_using_container_background_;
+ bool has_non_local_geometry_ = false;
+ bool painting_view_ = false;
+ bool painting_table_cell_ = false;
+ bool cell_using_container_background_ = false;
+ bool root_element_has_transform_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc
index 680513699b2..ca0d9bfebb3 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_flow_paint_invalidator.cc
@@ -6,6 +6,8 @@
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/paint/box_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_invalidator.h"
@@ -58,17 +60,31 @@ void BlockFlowPaintInvalidator::InvalidateDisplayItemClients(
reason == PaintInvalidationReason::kSelection)
return;
- // It's the RootInlineBox that paints the ::first-line background. Note that
- // since it may be expensive to figure out if the first line is affected by
- // any ::first-line selectors at all, we just invalidate it unconditionally
- // which is typically cheaper.
- if (RootInlineBox* line = block_flow_.FirstRootBox()) {
- if (line->IsFirstLineStyle()) {
- object_paint_invalidator.InvalidateDisplayItemClient(*line, reason);
+ NGInlineCursor cursor(block_flow_);
+ if (cursor) {
+ // Line boxes record hit test data (see NGBoxFragmentPainter::PaintLineBox)
+ // and should be invalidated if they change.
+ bool invalidate_all_lines = block_flow_.HasEffectiveAllowedTouchAction();
+
+ for (cursor.MoveToFirstLine(); cursor; cursor.MoveToNextLine()) {
+ // The first line NGLineBoxFragment paints the ::first-line background.
+ // Because it may be expensive to figure out if the first line is affected
+ // by any ::first-line selectors at all, we just invalidate
+ // unconditionally which is typically cheaper.
+ if (invalidate_all_lines || cursor.Current().UsesFirstLineStyle()) {
+ DCHECK(cursor.Current().GetDisplayItemClient());
+ object_paint_invalidator.InvalidateDisplayItemClient(
+ *cursor.Current().GetDisplayItemClient(), reason);
+ }
+ if (!invalidate_all_lines)
+ break;
}
- } else if (paint_fragment) {
- NGPaintFragment* line = paint_fragment->FirstLineBox();
- if (line && line->PhysicalFragment().UsesFirstLineStyle()) {
+ } else if (RootInlineBox* line = block_flow_.FirstRootBox()) {
+ // It's the RootInlineBox that paints the ::first-line background. Note that
+ // since it may be expensive to figure out if the first line is affected by
+ // any ::first-line selectors at all, we just invalidate it unconditionally
+ // which is typically cheaper.
+ if (line->IsFirstLineStyle()) {
object_paint_invalidator.InvalidateDisplayItemClient(*line, reason);
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter.cc b/chromium/third_party/blink/renderer/core/paint/block_painter.cc
index 4364b0e0342..60a7b22aa39 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter.cc
@@ -146,7 +146,7 @@ void BlockPainter::PaintChild(const LayoutBox& child,
// paints floats in regular tree order (the FloatingObjects list is only used
// by legacy layout).
if (paint_info.phase != PaintPhase::kFloat &&
- paint_info.phase != PaintPhase::kSelection &&
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip)
return;
@@ -182,7 +182,7 @@ void BlockPainter::PaintInlineBox(const InlineBox& inline_box,
const PaintInfo& paint_info) {
if (paint_info.phase != PaintPhase::kForeground &&
paint_info.phase != PaintPhase::kForcedColorsModeBackplate &&
- paint_info.phase != PaintPhase::kSelection)
+ paint_info.phase != PaintPhase::kSelectionDragImage)
return;
// Text clips are painted only for the direct inline children of the object
@@ -287,7 +287,7 @@ void BlockPainter::PaintBlockFlowContents(const PaintInfo& paint_info,
To<LayoutBlockFlow>(layout_block_).GetFloatingObjects();
const PaintPhase paint_phase = paint_info.phase;
if (!floating_objects || !(paint_phase == PaintPhase::kFloat ||
- paint_phase == PaintPhase::kSelection ||
+ paint_phase == PaintPhase::kSelectionDragImage ||
paint_phase == PaintPhase::kTextClip)) {
return;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
index 00021a4679e..070d7578f99 100644
--- a/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/block_painter_test.cc
@@ -12,7 +12,6 @@
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h"
using testing::ElementsAre;
@@ -71,93 +70,107 @@ TEST_F(BlockPainterTouchActionTest, TouchActionRectsWithoutPaint) {
</div>
)HTML");
- // Initially there should be no hit test display items because there is no
- // touch action.
+ // Initially there should be no hit test data because there is no touch
+ // action.
const auto& scrolling_client = ViewScrollingBackgroundClient();
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
+ PaintChunk::Id root_chunk_id(scrolling_client, kDocumentBackgroundType);
+ auto root_chunk_properties =
+ GetLayoutView().FirstFragment().ContentsProperties();
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties)));
- // Add a touch action to parent and ensure that hit test display items are
- // created for both the parent and the visible child.
+ // Add a touch action to parent and ensure that hit test data are created
+ // for both the parent and the visible child.
auto* parent_element = GetElementById("parent");
parent_element->setAttribute(html_names::kClassAttr, "touchActionNone");
UpdateAllLifecyclePhasesForTest();
- auto* parent = GetLayoutObjectByElementId("parent");
- auto* child_visible = GetLayoutObjectByElementId("childVisible");
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(parent, DisplayItem::kHitTest),
- IsSameId(child_visible, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
+ HitTestData hit_test_data;
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 100)},
+ {IntRect(0, 0, 200, 25)}};
+ EXPECT_THAT(RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 1, root_chunk_id,
+ root_chunk_properties, &hit_test_data)));
- // Remove the touch action from parent and ensure no hit test display items
- // are left.
+ // Remove the touch action from parent and ensure no hit test data are left.
parent_element->removeAttribute(html_names::kClassAttr);
UpdateAllLifecyclePhasesForTest();
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties)));
}
TEST_F(BlockPainterTouchActionTest, TouchActionRectSubsequenceCaching) {
SetBodyInnerHTML(R"HTML(
<style>
body { margin: 0; }
+ #stacking-context {
+ position: absolute;
+ z-index: 1;
+ }
#touchaction {
width: 100px;
height: 100px;
touch-action: none;
}
- #sibling {
- width: 100px;
- height: 100px;
- background: blue;
- }
</style>
- <div id='touchaction'></div>
+ <div id='stacking-context'>
+ <div id='touchaction'></div>
+ </div>
)HTML");
const auto& scrolling_client = ViewScrollingBackgroundClient();
const auto* touchaction = GetLayoutObjectByElementId("touchaction");
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(touchaction, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
- const auto& hit_test_client = *touchaction->EnclosingLayer();
+ const auto& hit_test_client =
+ *ToLayoutBox(GetLayoutObjectByElementId("stacking-context"))->Layer();
EXPECT_SUBSEQUENCE(hit_test_client, 1, 2);
PaintChunk::Id root_chunk_id(scrolling_client, kDocumentBackgroundType);
auto root_chunk_properties =
GetLayoutView().FirstFragment().ContentsProperties();
- PaintChunk::Id hit_test_chunk_id(hit_test_client,
- kNonScrollingBackgroundChunkType);
+ PaintChunk::Id hit_test_chunk_id(hit_test_client, DisplayItem::kLayerChunk);
auto hit_test_chunk_properties = touchaction->EnclosingLayer()
->GetLayoutObject()
.FirstFragment()
.ContentsProperties();
HitTestData hit_test_data;
- hit_test_data.touch_action_rects.emplace_back(LayoutRect(0, 0, 100, 100));
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 100)}};
EXPECT_THAT(
RootPaintController().PaintChunks(),
- ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
- IsPaintChunk(1, 2, hit_test_chunk_id,
- hit_test_chunk_properties, hit_test_data)));
+ ElementsAre(
+ IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
+ IsPaintChunk(1, 1, hit_test_chunk_id, hit_test_chunk_properties,
+ &hit_test_data, IntRect(0, 0, 100, 100))));
// Trigger a repaint with the whole HTML subsequence cached.
GetLayoutView().Layer()->SetNeedsRepaint();
EXPECT_TRUE(PaintWithoutCommit());
- EXPECT_EQ(2, NumCachedNewItems());
+ EXPECT_EQ(1, NumCachedNewItems());
CommitAndFinishCycle();
EXPECT_SUBSEQUENCE(hit_test_client, 1, 2);
EXPECT_THAT(
RootPaintController().PaintChunks(),
- ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
- IsPaintChunk(1, 2, hit_test_chunk_id,
- hit_test_chunk_properties, hit_test_data)));
+ ElementsAre(
+ IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
+ IsPaintChunk(1, 1, hit_test_chunk_id, hit_test_chunk_properties,
+ &hit_test_data, IntRect(0, 0, 100, 100))));
}
TEST_F(BlockPainterTouchActionTest, TouchActionRectPaintCaching) {
@@ -180,45 +193,34 @@ TEST_F(BlockPainterTouchActionTest, TouchActionRectPaintCaching) {
)HTML");
const auto& scrolling_client = ViewScrollingBackgroundClient();
- const auto* touchaction = GetLayoutObjectByElementId("touchaction");
auto* sibling_element = GetElementById("sibling");
const auto* sibling = sibling_element->GetLayoutObject();
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(touchaction, DisplayItem::kHitTest),
IsSameId(sibling, kBackgroundType)));
PaintChunk::Id root_chunk_id(scrolling_client, kDocumentBackgroundType);
auto root_chunk_properties =
GetLayoutView().FirstFragment().ContentsProperties();
- PaintChunk::Id hit_test_chunk_id(*touchaction->EnclosingLayer(),
- kNonScrollingBackgroundChunkType);
- auto hit_test_chunk_properties = touchaction->EnclosingLayer()
- ->GetLayoutObject()
- .FirstFragment()
- .ContentsProperties();
HitTestData hit_test_data;
- hit_test_data.touch_action_rects.emplace_back(LayoutRect(0, 0, 100, 100));
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 100)}};
- EXPECT_THAT(
- RootPaintController().PaintChunks(),
- ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
- IsPaintChunk(1, 3, hit_test_chunk_id,
- hit_test_chunk_properties, hit_test_data)));
+ EXPECT_THAT(RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 2, root_chunk_id,
+ root_chunk_properties, &hit_test_data)));
sibling_element->setAttribute(html_names::kStyleAttr, "background: green;");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(PaintWithoutCommit());
// Only the background display item of the sibling should be invalidated.
- EXPECT_EQ(2, NumCachedNewItems());
+ EXPECT_EQ(1, NumCachedNewItems());
CommitAndFinishCycle();
- EXPECT_THAT(
- RootPaintController().PaintChunks(),
- ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
- IsPaintChunk(1, 3, hit_test_chunk_id,
- hit_test_chunk_properties, hit_test_data)));
+ EXPECT_THAT(RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 2, root_chunk_id,
+ root_chunk_properties, &hit_test_data)));
}
TEST_F(BlockPainterTouchActionTest, TouchActionRectScrollingContents) {
@@ -251,25 +253,21 @@ TEST_F(BlockPainterTouchActionTest, TouchActionRectScrollingContents) {
auto* scroller = ToLayoutBoxModelObject(scroller_element->GetLayoutObject());
const auto& scroller_client =
scroller->GetScrollableArea()->GetScrollingBackgroundDisplayItemClient();
- auto* child_element = GetElementById("child");
- auto* child = child_element->GetLayoutObject();
auto& non_scroller_paint_controller = RootPaintController();
auto& scroller_paint_controller = scroller->GetScrollableArea()
->Layer()
->GraphicsLayerBacking()
->GetPaintController();
EXPECT_THAT(scroller_paint_controller.GetDisplayItemList(),
- ElementsAre(IsSameId(&scroller_client, kBackgroundType),
- IsSameId(&scroller_client, DisplayItem::kHitTest),
- IsSameId(child, DisplayItem::kHitTest)));
+ ElementsAre(IsSameId(&scroller_client, kBackgroundType)));
HitTestData hit_test_data;
- hit_test_data.touch_action_rects.emplace_back(LayoutRect(0, 0, 100, 400));
- hit_test_data.touch_action_rects.emplace_back(LayoutRect(0, 0, 10, 400));
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 400)},
+ {IntRect(0, 0, 10, 400)}};
EXPECT_THAT(
scroller_paint_controller.PaintChunks(),
ElementsAre(IsPaintChunk(
- 0, 3, PaintChunk::Id(*scroller, kScrollingBackgroundChunkType),
- scroller->FirstFragment().ContentsProperties(), hit_test_data)));
+ 0, 1, PaintChunk::Id(*scroller, kScrollingBackgroundChunkType),
+ scroller->FirstFragment().ContentsProperties(), &hit_test_data)));
EXPECT_THAT(non_scroller_paint_controller.GetDisplayItemList(),
ElementsAre(IsSameId(&root_client, kDocumentBackgroundType)));
@@ -309,24 +307,18 @@ TEST_F(BlockPainterTouchActionTest, TouchActionRectPaintChunkChanges) {
touchaction_element->setAttribute(html_names::kStyleAttr,
"touch-action: none;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(touchaction, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
PaintChunk::Id hit_test_chunk_id(*touchaction->EnclosingLayer(),
kNonScrollingBackgroundChunkType);
- auto hit_test_chunk_properties = touchaction->EnclosingLayer()
- ->GetLayoutObject()
- .FirstFragment()
- .ContentsProperties();
HitTestData hit_test_data;
- hit_test_data.touch_action_rects.emplace_back(LayoutRect(0, 0, 100, 100));
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 100)}};
- EXPECT_THAT(
- RootPaintController().PaintChunks(),
- ElementsAre(IsPaintChunk(0, 1, root_chunk_id, root_chunk_properties),
- IsPaintChunk(1, 2, hit_test_chunk_id,
- hit_test_chunk_properties, hit_test_data)));
+ EXPECT_THAT(RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 1, root_chunk_id,
+ root_chunk_properties, &hit_test_data)));
touchaction_element->removeAttribute(html_names::kStyleAttr);
UpdateAllLifecyclePhasesForTest();
@@ -358,35 +350,46 @@ TEST_F(BlockPainterTouchActionTest, TouchHandlerRectsWithoutPaint) {
</div>
)HTML");
- // Initially there should be no hit test display items because there are no
- // event handlers.
+ // Initially there should be no hit test data because there are no event
+ // handlers.
const auto& scrolling_client = ViewScrollingBackgroundClient();
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
- // Add an event listener to parent and ensure that hit test display items are
- // created for both the parent and child.
+ // Add an event listener to parent and ensure that hit test data are created
+ // for both the parent and child.
BlockPainterMockEventListener* callback =
MakeGarbageCollected<BlockPainterMockEventListener>();
auto* parent_element = GetElementById("parent");
parent_element->addEventListener(event_type_names::kTouchstart, callback);
UpdateAllLifecyclePhasesForTest();
- auto* parent = GetLayoutObjectByElementId("parent");
- auto* child = GetLayoutObjectByElementId("child");
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(parent, DisplayItem::kHitTest),
- IsSameId(child, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
+ HitTestData hit_test_data;
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 100)},
+ {IntRect(0, 0, 200, 50)}};
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(
+ 0, 1, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties(), &hit_test_data,
+ IntRect(0, 0, 800, 600))));
- // Remove the event handler from parent and ensure no hit test display items
- // are left.
+ // Remove the event handler from parent and ensure no hit test data are left.
parent_element->RemoveAllEventListeners();
UpdateAllLifecyclePhasesForTest();
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(
+ 0, 1, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties(), nullptr,
+ IntRect(0, 0, 800, 600))));
}
TEST_F(BlockPainterTouchActionTest, TouchActionRectsAcrossPaintChanges) {
@@ -403,21 +406,32 @@ TEST_F(BlockPainterTouchActionTest, TouchActionRectsAcrossPaintChanges) {
)HTML");
const auto& scrolling_client = ViewScrollingBackgroundClient();
- auto* parent = GetLayoutObjectByElementId("parent");
- auto* child = GetLayoutObjectByElementId("child");
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(parent, DisplayItem::kHitTest),
- IsSameId(child, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
+ HitTestData hit_test_data;
+ hit_test_data.touch_action_rects = {{IntRect(0, 0, 100, 100)},
+ {IntRect(0, 0, 200, 50)}};
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(
+ 0, 1, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties(), &hit_test_data,
+ IntRect(0, 0, 800, 600))));
- auto* child_element = GetElementById("parent");
+ auto* child_element = GetElementById("child");
child_element->setAttribute("style", "background: blue;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(parent, kBackgroundType),
- IsSameId(parent, DisplayItem::kHitTest),
- IsSameId(child, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
+ IsSameId(child_element->GetLayoutObject(), kBackgroundType)));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(
+ 0, 2, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties(), &hit_test_data,
+ IntRect(0, 0, 800, 600))));
}
TEST_F(BlockPainterTouchActionTest, ScrolledHitTestChunkProperties) {
@@ -445,24 +459,21 @@ TEST_F(BlockPainterTouchActionTest, ScrolledHitTestChunkProperties) {
const auto& scrolling_client = ViewScrollingBackgroundClient();
const auto* scroller =
To<LayoutBlock>(GetLayoutObjectByElementId("scroller"));
- const auto* child = GetLayoutObjectByElementId("child");
- EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType),
- IsSameId(scroller, DisplayItem::kHitTest),
- IsSameId(scroller, DisplayItem::kScrollHitTest),
- IsSameId(child, DisplayItem::kHitTest)));
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&scrolling_client, kDocumentBackgroundType)));
HitTestData scroller_touch_action_hit_test_data;
- scroller_touch_action_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 100, 100));
+ scroller_touch_action_hit_test_data.touch_action_rects = {
+ {IntRect(0, 0, 100, 100)}};
const auto& scrolling_contents_properties =
scroller->FirstFragment().ContentsProperties();
HitTestData scroll_hit_test_data;
- scroll_hit_test_data.SetScrollHitTest(
- &scrolling_contents_properties.Transform(), IntRect(0, 0, 100, 100));
+ scroll_hit_test_data.scroll_translation =
+ &scrolling_contents_properties.Transform();
+ scroll_hit_test_data.scroll_hit_test_rect = IntRect(0, 0, 100, 100);
HitTestData scrolled_hit_test_data;
- scrolled_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 200, 50));
+ scrolled_hit_test_data.touch_action_rects = {{IntRect(0, 0, 200, 50)}};
const auto& paint_chunks = RootPaintController().PaintChunks();
EXPECT_THAT(
@@ -470,29 +481,28 @@ TEST_F(BlockPainterTouchActionTest, ScrolledHitTestChunkProperties) {
ElementsAre(
IsPaintChunk(
0, 1, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
- GetLayoutView().FirstFragment().ContentsProperties()),
- IsPaintChunk(1, 2,
- PaintChunk::Id(*scroller->Layer(),
- kNonScrollingBackgroundChunkType),
- scroller->FirstFragment().LocalBorderBoxProperties(),
- scroller_touch_action_hit_test_data),
- IsPaintChunk(2, 3,
+ GetLayoutView().FirstFragment().ContentsProperties(), nullptr,
+ IntRect(0, 0, 800, 600)),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*scroller->Layer(), DisplayItem::kLayerChunk),
+ scroller->FirstFragment().LocalBorderBoxProperties(),
+ &scroller_touch_action_hit_test_data, IntRect(0, 0, 100, 100)),
+ IsPaintChunk(1, 1,
PaintChunk::Id(*scroller, DisplayItem::kScrollHitTest),
scroller->FirstFragment().LocalBorderBoxProperties(),
- scroll_hit_test_data),
+ &scroll_hit_test_data, IntRect(0, 0, 100, 100)),
IsPaintChunk(
- 3, 4,
- PaintChunk::Id(*scroller, kScrollingContentsBackgroundChunkType),
+ 1, 1,
+ PaintChunk::Id(*scroller, kClippedContentsBackgroundChunkType),
scroller->FirstFragment().ContentsProperties(),
- scrolled_hit_test_data)));
+ &scrolled_hit_test_data, IntRect(0, 0, 200, 50))));
const auto& scroller_paint_chunk = paint_chunks[1];
- EXPECT_EQ(IntRect(0, 0, 100, 100), scroller_paint_chunk.bounds);
// The hit test rect for the scroller itself should not be scrolled.
EXPECT_FALSE(scroller_paint_chunk.properties.Transform().ScrollNode());
const auto& scrolled_paint_chunk = paint_chunks[3];
- EXPECT_EQ(IntRect(0, 0, 200, 50), scrolled_paint_chunk.bounds);
// The hit test rect for the scrolled contents should be scrolled.
EXPECT_TRUE(scrolled_paint_chunk.properties.Transform().ScrollNode());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc
index eace1c00a23..49772004f87 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_border_painter.cc
@@ -289,20 +289,12 @@ LayoutRectOutsets DoubleStripeInsets(const BorderEdge edges[],
stripe));
}
-float ClampOrRound(float border_width) {
- // Make sure non-zero borders never disappear
- if (border_width > 0.0f && border_width <= 1.0f)
- return 1.0f;
-
- return roundf(border_width);
-}
-
void DrawSolidBorderRect(GraphicsContext& context,
const FloatRect& border_rect,
float border_width,
const Color& color) {
FloatRect stroke_rect(border_rect);
- border_width = ClampOrRound(border_width);
+ border_width = roundf(border_width);
stroke_rect.Inflate(-border_width / 2);
bool was_antialias = context.ShouldAntialias();
@@ -854,7 +846,7 @@ void BoxBorderPainter::PaintSide(GraphicsContext& context,
if (use_path)
path = &border_info.rounded_border_path;
else
- side_rect.SetHeight(ClampOrRound(edge.Width()));
+ side_rect.SetHeight(roundf(edge.Width()));
PaintOneBorderSide(context, side_rect, BoxSide::kTop, BoxSide::kLeft,
BoxSide::kRight, path, border_info.anti_alias, color,
@@ -869,7 +861,7 @@ void BoxBorderPainter::PaintSide(GraphicsContext& context,
if (use_path)
path = &border_info.rounded_border_path;
else
- side_rect.ShiftYEdgeTo(side_rect.MaxY() - ClampOrRound(edge.Width()));
+ side_rect.ShiftYEdgeTo(side_rect.MaxY() - roundf(edge.Width()));
PaintOneBorderSide(context, side_rect, BoxSide::kBottom, BoxSide::kLeft,
BoxSide::kRight, path, border_info.anti_alias, color,
@@ -884,7 +876,7 @@ void BoxBorderPainter::PaintSide(GraphicsContext& context,
if (use_path)
path = &border_info.rounded_border_path;
else
- side_rect.SetWidth(ClampOrRound(edge.Width()));
+ side_rect.SetWidth(roundf(edge.Width()));
PaintOneBorderSide(context, side_rect, BoxSide::kLeft, BoxSide::kTop,
BoxSide::kBottom, path, border_info.anti_alias, color,
@@ -899,7 +891,7 @@ void BoxBorderPainter::PaintSide(GraphicsContext& context,
if (use_path)
path = &border_info.rounded_border_path;
else
- side_rect.ShiftXEdgeTo(side_rect.MaxX() - ClampOrRound(edge.Width()));
+ side_rect.ShiftXEdgeTo(side_rect.MaxX() - roundf(edge.Width()));
PaintOneBorderSide(context, side_rect, BoxSide::kRight, BoxSide::kTop,
BoxSide::kBottom, path, border_info.anti_alias, color,
@@ -1017,9 +1009,8 @@ void BoxBorderPainter::PaintOneBorderSide(
ObjectPainter::DrawLineForBoxSide(
graphics_context, side_rect.X(), side_rect.Y(), side_rect.MaxX(),
side_rect.MaxY(), side, color, edge_to_render.BorderStyle(),
- miter1 != kNoMiter ? ClampOrRound(adjacent_edge1.Width()) : 0,
- miter2 != kNoMiter ? ClampOrRound(adjacent_edge2.Width()) : 0,
- antialias);
+ miter1 != kNoMiter ? roundf(adjacent_edge1.Width()) : 0,
+ miter2 != kNoMiter ? roundf(adjacent_edge2.Width()) : 0, antialias);
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
index 20136ea1566..d9462947cb3 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.cc
@@ -124,13 +124,24 @@ LayoutRectOutsets BoxModelObjectPainter::ComputePadding() const {
BoxPainterBase::FillLayerInfo BoxModelObjectPainter::GetFillLayerInfo(
const Color& color,
const FillLayer& bg_layer,
- BackgroundBleedAvoidance bleed_avoidance) const {
+ BackgroundBleedAvoidance bleed_avoidance,
+ bool is_painting_scrolling_background) const {
return BoxPainterBase::FillLayerInfo(
box_model_.GetDocument(), box_model_.StyleRef(),
box_model_.HasOverflowClip(), color, bg_layer, bleed_avoidance,
+ LayoutObject::ShouldRespectImageOrientation(&box_model_),
(flow_box_ ? flow_box_->IncludeLogicalLeftEdge() : true),
(flow_box_ ? flow_box_->IncludeLogicalRightEdge() : true),
- box_model_.IsInline());
+ box_model_.IsLayoutInline(), is_painting_scrolling_background);
+}
+
+bool BoxModelObjectPainter::IsPaintingScrollingBackground(
+ const PaintInfo& paint_info) const {
+ if (!box_model_.IsBox())
+ return false;
+
+ const auto& this_box = ToLayoutBox(box_model_);
+ return BoxDecorationData::IsPaintingScrollingBackground(paint_info, this_box);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.h b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.h
index eed39f2c998..03f15100911 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/box_model_object_painter.h
@@ -33,7 +33,9 @@ class BoxModelObjectPainter : public BoxPainterBase {
BoxPainterBase::FillLayerInfo GetFillLayerInfo(
const Color&,
const FillLayer&,
- BackgroundBleedAvoidance) const override;
+ BackgroundBleedAvoidance,
+ bool is_painting_scrolling_background) const override;
+ bool IsPaintingScrollingBackground(const PaintInfo&) const override;
void PaintTextClipMask(GraphicsContext&,
const IntRect& mask_rect,
diff --git a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
index 985e5a237f4..53a09c5d9e4 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator.cc
@@ -17,7 +17,7 @@ namespace blink {
bool BoxPaintInvalidator::HasEffectiveBackground() {
// The view can paint background not from the style.
- if (box_.IsLayoutView())
+ if (IsA<LayoutView>(box_))
return true;
return box_.StyleRef().HasBackground() && !box_.BackgroundTransfersToView();
}
@@ -184,27 +184,14 @@ bool BoxPaintInvalidator::BackgroundGeometryDependsOnLayoutOverflowRect() {
bool BoxPaintInvalidator::BackgroundPaintsOntoScrollingContentsLayer() {
if (!HasEffectiveBackground())
return false;
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- return box_.GetBackgroundPaintLocation() &
- kBackgroundPaintInScrollingContents;
- }
- if (!box_.HasLayer())
- return false;
- if (auto* mapping = box_.Layer()->GetCompositedLayerMapping())
- return mapping->BackgroundPaintsOntoScrollingContentsLayer();
- return false;
+ return box_.GetBackgroundPaintLocation() &
+ kBackgroundPaintInScrollingContents;
}
bool BoxPaintInvalidator::BackgroundPaintsOntoMainGraphicsLayer() {
if (!HasEffectiveBackground())
return false;
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return box_.GetBackgroundPaintLocation() & kBackgroundPaintInGraphicsLayer;
- if (!box_.HasLayer())
- return true;
- if (auto* mapping = box_.Layer()->GetCompositedLayerMapping())
- return mapping->BackgroundPaintsOntoGraphicsLayer();
- return true;
+ return box_.GetBackgroundPaintLocation() & kBackgroundPaintInGraphicsLayer;
}
bool BoxPaintInvalidator::ShouldFullyInvalidateBackgroundOnLayoutOverflowChange(
@@ -227,9 +214,9 @@ bool BoxPaintInvalidator::ShouldFullyInvalidateBackgroundOnLayoutOverflowChange(
BoxPaintInvalidator::BackgroundInvalidationType
BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
- DCHECK(box_.IsLayoutView());
+ DCHECK(IsA<LayoutView>(box_));
- const auto& layout_view = ToLayoutView(box_);
+ const auto& layout_view = To<LayoutView>(box_);
auto new_background_rect = layout_view.BackgroundRect();
auto old_background_rect = layout_view.PreviousBackgroundRect();
layout_view.SetPreviousBackgroundRect(new_background_rect);
@@ -250,18 +237,31 @@ BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
layout_view.BackgroundNeedsFullPaintInvalidation())
return BackgroundInvalidationType::kFull;
- // LayoutView's non-fixed-attachment background is positioned in the
- // document element and needs to invalidate if the size changes.
- // See: https://drafts.csswg.org/css-backgrounds-3/#root-background.
- if (BackgroundGeometryDependsOnLayoutOverflowRect()) {
- Element* document_element = box_.GetDocument().documentElement();
+ if (Element* document_element = box_.GetDocument().documentElement()) {
if (document_element) {
- const auto* document_background = document_element->GetLayoutObject();
- if (document_background && document_background->IsBox()) {
- const auto* document_background_box = ToLayoutBox(document_background);
- if (ShouldFullyInvalidateBackgroundOnLayoutOverflowChange(
- document_background_box->PreviousPhysicalLayoutOverflowRect(),
- document_background_box->PhysicalLayoutOverflowRect())) {
+ if (const auto* document_element_object =
+ document_element->GetLayoutObject()) {
+ // LayoutView's non-fixed-attachment background is positioned in the
+ // document element and needs to invalidate if the size changes.
+ // See: https://drafts.csswg.org/css-backgrounds-3/#root-background.
+ if (BackgroundGeometryDependsOnLayoutOverflowRect()) {
+ if (document_element_object->IsBox()) {
+ const auto* document_background_box =
+ ToLayoutBox(document_element_object);
+ if (ShouldFullyInvalidateBackgroundOnLayoutOverflowChange(
+ document_background_box
+ ->PreviousPhysicalLayoutOverflowRect(),
+ document_background_box->PhysicalLayoutOverflowRect())) {
+ return BackgroundInvalidationType::kFull;
+ }
+ }
+ }
+
+ // The document background paints with a transform but nevertheless
+ // extended onto an infinite canvas. In cases where it has a transform
+ // we cna't apply incremental invalidation, because the visual rect is
+ // no longer axis-aligned to the LayoutView.
+ if (document_element_object->StyleRef().HasTransform()) {
return BackgroundInvalidationType::kFull;
}
}
@@ -275,16 +275,6 @@ BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
BoxPaintInvalidator::BackgroundInvalidationType
BoxPaintInvalidator::ComputeBackgroundInvalidation(
bool& should_invalidate_all_layers) {
- // Need to fully invalidate the background on all layers if background paint
- // location changed.
- auto new_background_location = box_.GetBackgroundPaintLocation();
- if (new_background_location != box_.PreviousBackgroundPaintLocation()) {
- should_invalidate_all_layers = true;
- box_.GetMutableForPainting().SetPreviousBackgroundPaintLocation(
- new_background_location);
- return BackgroundInvalidationType::kFull;
- }
-
// If background changed, we may paint the background on different graphics
// layer, so we need to fully invalidate the background on all layers.
if (box_.BackgroundNeedsFullPaintInvalidation()) {
@@ -332,7 +322,7 @@ void BoxPaintInvalidator::InvalidateBackground() {
bool should_invalidate_all_layers = false;
auto background_invalidation_type =
ComputeBackgroundInvalidation(should_invalidate_all_layers);
- if (box_.IsLayoutView()) {
+ if (IsA<LayoutView>(box_)) {
background_invalidation_type = std::max(
background_invalidation_type, ComputeViewBackgroundInvalidation());
}
@@ -394,9 +384,6 @@ bool BoxPaintInvalidator::
if (context_.fragment_data->VisualRect().IsEmpty())
return false;
- if (box_.PaintedOutputOfObjectHasNoEffectRegardlessOfSize())
- return false;
-
const ComputedStyle& style = box_.StyleRef();
// Background and mask layers can depend on other boxes than border box. See
diff --git a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
index 714a3777769..c6456900950 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_paint_invalidator_test.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
#include "third_party/blink/renderer/core/paint/paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -18,11 +19,11 @@
namespace blink {
-class BoxPaintInvalidatorTest : public PaintControllerPaintTest {
+using ::testing::UnorderedElementsAre;
+
+class BoxPaintInvalidatorTest : public PaintAndRasterInvalidationTest {
public:
- BoxPaintInvalidatorTest()
- : PaintControllerPaintTest(
- MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
+ BoxPaintInvalidatorTest() = default;
protected:
PaintInvalidationReason ComputePaintInvalidationReason(
@@ -60,6 +61,7 @@ class BoxPaintInvalidatorTest : public PaintControllerPaintTest {
auto& box = *ToLayoutBox(target.GetLayoutObject());
auto visual_rect = box.FirstFragment().VisualRect();
auto paint_offset = box.FirstFragment().PaintOffset();
+ box.SetShouldCheckForPaintInvalidation();
// No geometry change.
EXPECT_EQ(PaintInvalidationReason::kNone,
@@ -68,7 +70,13 @@ class BoxPaintInvalidatorTest : public PaintControllerPaintTest {
target.setAttribute(
html_names::kStyleAttr,
target.getAttribute(html_names::kStyleAttr) + "; width: 200px");
- GetDocument().View()->UpdateLifecycleToCompositingInputsClean();
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
+ } else {
+ GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
+ DocumentUpdateReason::kTest);
+ }
// Simulate that PaintInvalidator updates visual rect.
box.GetMutableForPainting().SetVisualRect(
IntRect(visual_rect.Location(), RoundedIntSize(box.Size())));
@@ -109,7 +117,10 @@ class BoxPaintInvalidatorTest : public PaintControllerPaintTest {
INSTANTIATE_PAINT_TEST_SUITE_P(BoxPaintInvalidatorTest);
-TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonPaintingNothing) {
+// Paint invalidation for empty content is needed for updating composited layer
+// bounds for correct composited hit testing. It won't cause raster invalidation
+// (tested in paint_and_raster_invalidation_test.cc).
+TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonEmptyContent) {
SetUpHTML();
auto& target = *GetDocument().getElementById("target");
auto& box = *ToLayoutBox(target.GetLayoutObject());
@@ -117,7 +128,7 @@ TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonPaintingNothing) {
target.setAttribute(html_names::kClassAttr, "");
UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(box.PaintedOutputOfObjectHasNoEffectRegardlessOfSize());
+ box.SetShouldCheckForPaintInvalidation();
auto visual_rect = box.FirstFragment().VisualRect();
// No geometry change.
@@ -126,19 +137,22 @@ TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonPaintingNothing) {
ComputePaintInvalidationReason(box, visual_rect, visual_rect.Location()));
// Paint offset change.
- EXPECT_EQ(PaintInvalidationReason::kNone,
- ComputePaintInvalidationReason(
- box, visual_rect, visual_rect.Location() + IntSize(10, 20)));
+ auto old_visual_rect = visual_rect;
+ old_visual_rect.Move(IntSize(10, 20));
+ EXPECT_EQ(PaintInvalidationReason::kGeometry,
+ ComputePaintInvalidationReason(box, old_visual_rect,
+ old_visual_rect.Location()));
// Visual rect size change.
- auto old_visual_rect = visual_rect;
+ old_visual_rect = visual_rect;
target.setAttribute(html_names::kStyleAttr, "width: 200px");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
// Simulate that PaintInvalidator updates visual rect.
box.GetMutableForPainting().SetVisualRect(
IntRect(visual_rect.Location(), RoundedIntSize(box.Size())));
- EXPECT_EQ(PaintInvalidationReason::kNone,
+ EXPECT_EQ(PaintInvalidationReason::kIncremental,
ComputePaintInvalidationReason(box, old_visual_rect,
old_visual_rect.Location()));
}
@@ -164,7 +178,8 @@ TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonBasic) {
// Visual rect size change.
auto old_visual_rect = visual_rect;
target.setAttribute(html_names::kStyleAttr, "background: blue; width: 200px");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
// Simulate that PaintInvalidator updates visual rect.
box.GetMutableForPainting().SetVisualRect(
IntRect(visual_rect.Location(), RoundedIntSize(box.Size())));
@@ -193,6 +208,27 @@ TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonBasic) {
box, visual_rect, visual_rect.Location() + IntSize(10, 20)));
}
+TEST_P(BoxPaintInvalidatorTest,
+ InvalidateLineBoxHitTestOnCompositingStyleChange) {
+ ScopedPaintUnderInvalidationCheckingForTest under_invalidation_checking(true);
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #target {
+ width: 100px;
+ height: 100px;
+ touch-action: none;
+ }
+ </style>
+ <div id="target" style="will-change: transform;">a<br>b</div>
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+ auto& target = *GetDocument().getElementById("target");
+ target.setAttribute(html_names::kStyleAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+ // This test passes if no underinvalidation occurs.
+}
+
TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonOtherCases) {
SetUpHTML();
auto& target = *GetDocument().getElementById("target");
@@ -211,9 +247,6 @@ TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonOtherCases) {
target.setAttribute(html_names::kStyleAttr, "filter: blur(5px)");
ExpectFullPaintInvalidationOnGeometryChange("With filter");
- target.setAttribute(html_names::kStyleAttr, "outline: 2px solid blue");
- ExpectFullPaintInvalidationOnGeometryChange("With outline");
-
target.setAttribute(html_names::kStyleAttr, "box-shadow: inset 3px 2px");
ExpectFullPaintInvalidationOnGeometryChange("With box-shadow");
@@ -222,4 +255,50 @@ TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonOtherCases) {
ExpectFullPaintInvalidationOnGeometryChange("With clip-path");
}
+TEST_P(BoxPaintInvalidatorTest, ComputePaintInvalidationReasonOutline) {
+ SetUpHTML();
+ auto& target = *GetDocument().getElementById("target");
+ auto* object = target.GetLayoutObject();
+
+ GetDocument().View()->SetTracksRasterInvalidations(true);
+ target.setAttribute(html_names::kStyleAttr, "outline: 2px solid blue;");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+ UnorderedElementsAre(RasterInvalidationInfo{
+ object, object->DebugName(), IntRect(0, 0, 72, 142),
+ PaintInvalidationReason::kStyle}));
+ GetDocument().View()->SetTracksRasterInvalidations(false);
+
+ GetDocument().View()->SetTracksRasterInvalidations(true);
+ target.setAttribute(html_names::kStyleAttr,
+ "outline: 2px solid blue; width: 100px;");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+ UnorderedElementsAre(RasterInvalidationInfo{
+ object, object->DebugName(), IntRect(0, 0, 122, 142),
+ PaintInvalidationReason::kGeometry}));
+ GetDocument().View()->SetTracksRasterInvalidations(false);
+}
+
+TEST_P(BoxPaintInvalidatorTest, InvalidateHitTestOnCompositingStyleChange) {
+ ScopedPaintUnderInvalidationCheckingForTest under_invalidation_checking(true);
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #target {
+ width: 400px;
+ height: 300px;
+ overflow: hidden;
+ touch-action: none;
+ }
+ </style>
+ <div id="target" style="will-change: transform;"></div>
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+ auto& target = *GetDocument().getElementById("target");
+ target.setAttribute(html_names::kStyleAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+ // This test passes if no underinvalidation occurs.
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter.cc b/chromium/third_party/blink/renderer/core/paint/box_painter.cc
index 56c647e4f24..be14cf89e05 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter.cc
@@ -29,9 +29,7 @@
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h"
namespace blink {
@@ -48,9 +46,8 @@ void BoxPainter::PaintChildren(const PaintInfo& paint_info) {
PaintInfo child_info(paint_info);
for (LayoutObject* child = layout_box_.SlowFirstChild(); child;
child = child->NextSibling()) {
- if (child->IsSVGForeignObject()) {
- SVGForeignObjectPainter(ToLayoutSVGForeignObject(*child))
- .PaintLayer(paint_info);
+ if (auto* foreign_object = DynamicTo<LayoutSVGForeignObject>(*child)) {
+ SVGForeignObjectPainter(*foreign_object).PaintLayer(paint_info);
} else {
child->Paint(child_info);
}
@@ -121,20 +118,6 @@ void BoxPainter::PaintBoxDecorationBackground(
RecordScrollHitTestData(paint_info, *background_client);
}
-bool BoxPainter::BackgroundIsKnownToBeOpaque(const PaintInfo& paint_info) {
- // If the box has multiple fragments, its VisualRect is the bounding box of
- // all fragments' visual rects, which is likely to cover areas that are not
- // covered by painted background.
- if (layout_box_.FirstFragment().NextFragment())
- return false;
-
- PhysicalRect bounds =
- BoxDecorationData::IsPaintingScrollingBackground(paint_info, layout_box_)
- ? layout_box_.PhysicalLayoutOverflowRect()
- : layout_box_.PhysicalSelfVisualOverflowRect();
- return layout_box_.BackgroundIsKnownToBeOpaqueInRect(bounds);
-}
-
void BoxPainter::PaintBoxDecorationBackgroundWithRect(
const PaintInfo& paint_info,
const PhysicalRect& paint_rect,
@@ -142,17 +125,9 @@ void BoxPainter::PaintBoxDecorationBackgroundWithRect(
const ComputedStyle& style = layout_box_.StyleRef();
base::Optional<DisplayItemCacheSkipper> cache_skipper;
- // Disable cache in under-invalidation checking mode for MediaSliderPart
- // because we always paint using the latest data (buffered ranges, current
- // time and duration) which may be different from the cached data, and for
- // delayed-invalidation object because it may change before it's actually
- // invalidated. Note that we still report harmless under-invalidation of
- // non-delayed-invalidation animated background, which should be ignored.
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
- (style.EffectiveAppearance() == kMediaSliderPart ||
- layout_box_.ShouldDelayFullPaintInvalidation())) {
+ BoxPainterBase::ShouldSkipPaintUnderInvalidationChecking(layout_box_))
cache_skipper.emplace(paint_info.context);
- }
BoxDecorationData box_decoration_data(paint_info, layout_box_);
if (!box_decoration_data.ShouldPaint())
@@ -167,11 +142,6 @@ void BoxPainter::PaintBoxDecorationBackgroundWithRect(
DisplayItem::kBoxDecorationBackground);
GraphicsContextStateSaver state_saver(paint_info.context, false);
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- paint_rect.EdgesOnPixelBoundaries() &&
- BackgroundIsKnownToBeOpaque(paint_info))
- recorder.SetKnownToBeOpaque();
-
bool needs_end_layer = false;
// FIXME: Should eventually give the theme control over whether the box
// shadow should paint, since controls could have custom shadows of their
@@ -293,8 +263,8 @@ void BoxPainter::PaintMaskImages(const PaintInfo& paint_info,
void BoxPainter::RecordHitTestData(const PaintInfo& paint_info,
const PhysicalRect& paint_rect,
const DisplayItemClient& background_client) {
- // Hit test display items are only needed for compositing. This flag is used
- // for for printing and drag images which do not need hit testing.
+ // Hit test data are only needed for compositing. This flag is used for for
+ // printing and drag images which do not need hit testing.
if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
return;
@@ -302,20 +272,19 @@ void BoxPainter::RecordHitTestData(const PaintInfo& paint_info,
if (layout_box_.StyleRef().Visibility() != EVisibility::kVisible)
return;
- auto touch_action = layout_box_.EffectiveAllowedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
+ if (!paint_info.FragmentToPaint(layout_box_))
return;
- HitTestDisplayItem::Record(
- paint_info.context, background_client,
- HitTestRect(paint_rect.ToLayoutRect(), touch_action));
+ paint_info.context.GetPaintController().RecordHitTestData(
+ background_client, PixelSnappedIntRect(paint_rect),
+ layout_box_.EffectiveAllowedTouchAction());
}
void BoxPainter::RecordScrollHitTestData(
const PaintInfo& paint_info,
const DisplayItemClient& background_client) {
- // Hit test display items are only needed for compositing. This flag is used
- // for for printing and drag images which do not need hit testing.
+ // Scroll hit test data are only needed for compositing. This flag is used for
+ // printing and drag images which do not need hit testing.
if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
return;
@@ -334,25 +303,24 @@ void BoxPainter::RecordScrollHitTestData(
if (layout_box_.GetScrollableArea()->ScrollsOverflow()) {
const auto* properties = fragment->PaintProperties();
- // If there is an associated scroll node, emit a scroll hit test display
- // item.
+ // If there is an associated scroll node, emit scroll hit test data.
if (properties && properties->Scroll()) {
DCHECK(properties->ScrollTranslation());
- // The local border box properties are used instead of the contents
- // properties so that the scroll hit test is not clipped or scrolled.
- ScopedPaintChunkProperties scroll_hit_test_properties(
- paint_info.context.GetPaintController(),
- fragment->LocalBorderBoxProperties(), background_client,
- DisplayItem::kScrollHitTest);
- ScrollHitTestDisplayItem::Record(
- paint_info.context, background_client, DisplayItem::kScrollHitTest,
+ // We record scroll hit test data in the local border box properties
+ // instead of the contents properties so that the scroll hit test is not
+ // clipped or scrolled.
+ auto& paint_controller = paint_info.context.GetPaintController();
+ DCHECK_EQ(fragment->LocalBorderBoxProperties(),
+ paint_controller.CurrentPaintChunkProperties());
+ paint_controller.RecordScrollHitTestData(
+ background_client, DisplayItem::kScrollHitTest,
properties->ScrollTranslation(), fragment->VisualRect());
}
}
ScrollableAreaPainter(*layout_box_.GetScrollableArea())
- .RecordResizerScrollHitTestData(
- paint_info.context, fragment->PaintOffset(), background_client);
+ .RecordResizerScrollHitTestData(paint_info.context,
+ fragment->PaintOffset());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter.h b/chromium/third_party/blink/renderer/core/paint/box_painter.h
index 0b79434cf20..18322986bea 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter.h
@@ -38,21 +38,19 @@ class BoxPainter {
const PhysicalRect&,
const DisplayItemClient& background_client);
- // Paint a hit test display item and record hit test data. This should be
- // called in the background paint phase even if there is no other painted
- // content.
+ // Expands the bounds of the current paint chunk for hit test, and records
+ // special touch action if any. This should be called in the background paint
+ // phase even if there is no other painted content.
void RecordHitTestData(const PaintInfo&,
const PhysicalRect& paint_rect,
const DisplayItemClient& background_client);
- // Paint a scroll hit test display item and record scroll hit test data. This
- // should be called in the background paint phase even if there is no other
- // painted content.
+ // This should be called in the background paint phase even if there is no
+ // other painted content.
void RecordScrollHitTestData(const PaintInfo&,
const DisplayItemClient& background_client);
private:
- bool BackgroundIsKnownToBeOpaque(const PaintInfo&);
void PaintBackground(const PaintInfo&,
const PhysicalRect&,
const Color& background_color,
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
index 597dbee509e..660f62adc5b 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
+#include "third_party/blink/renderer/core/layout/layout_progress.h"
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
#include "third_party/blink/renderer/core/paint/box_border_painter.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
@@ -22,6 +23,7 @@
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/core/style/style_fetched_image.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+#include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/graphics/scoped_interpolation_quality.h"
@@ -274,11 +276,14 @@ BoxPainterBase::FillLayerInfo::FillLayerInfo(
Color bg_color,
const FillLayer& layer,
BackgroundBleedAvoidance bleed_avoidance,
+ RespectImageOrientationEnum respect_image_orientation,
bool include_left,
bool include_right,
- bool is_inline)
+ bool is_inline,
+ bool is_painting_scrolling_background)
: image(layer.GetImage()),
color(bg_color),
+ respect_image_orientation(respect_image_orientation),
include_left_edge(include_left),
include_right_edge(include_right),
is_bottom_layer(!layer.Next()),
@@ -315,7 +320,7 @@ BoxPainterBase::FillLayerInfo::FillLayerInfo(
// BorderFillBox radius clipping is taken care of by
// BackgroundBleedClip{Only,Layer}
is_rounded_fill =
- has_rounded_border &&
+ has_rounded_border && !is_painting_scrolling_background &&
!(is_border_fill && BleedAvoidanceIsClipping(bleed_avoidance));
should_paint_image = image && image->CanRender();
@@ -369,6 +374,25 @@ FloatRect ComputeSubsetForBackground(const FloatRect& phase_and_size,
subset.Height() / scale.Height());
}
+FloatRect SnapSourceRectIfNearIntegral(const FloatRect src_rect) {
+ // Round to avoid filtering pulling in neighboring pixels, for the
+ // common case of sprite maps, but only if we're close to an integral size.
+ // "Close" in this context means we will allow floating point inaccuracy,
+ // when converted to layout units, to be at most one LayoutUnit::Epsilon and
+ // still snap.
+ if (std::abs(std::round(src_rect.X()) - src_rect.X()) <=
+ LayoutUnit::Epsilon() &&
+ std::abs(std::round(src_rect.Y()) - src_rect.Y()) <=
+ LayoutUnit::Epsilon() &&
+ std::abs(std::round(src_rect.MaxX()) - src_rect.MaxX()) <=
+ LayoutUnit::Epsilon() &&
+ std::abs(std::round(src_rect.MaxY()) - src_rect.MaxY()) <=
+ LayoutUnit::Epsilon()) {
+ return FloatRect(RoundedIntRect(src_rect));
+ }
+ return src_rect;
+}
+
// The unsnapped_subset_size should be the target painting area implied by the
// content, without any snapping applied. It is necessary to correctly
// compute the subset of the source image to paint into the destination.
@@ -385,14 +409,21 @@ void DrawTiledBackground(GraphicsContext& context,
const FloatSize& tile_size,
SkBlendMode op,
const FloatSize& repeat_spacing,
- bool has_filter_property) {
+ bool has_filter_property,
+ RespectImageOrientationEnum respect_orientation) {
DCHECK(!tile_size.IsEmpty());
// Use the intrinsic size of the image if it has one, otherwise force the
// generated image to be the tile size.
FloatSize intrinsic_tile_size(image->Size());
FloatSize scale(1, 1);
- if (!image->HasIntrinsicSize()) {
+ if (!image->HasIntrinsicSize() ||
+ // TODO(crbug.com/1042783): This is not checking for real empty image
+ // (for which we have checked and skipped the whole FillLayer), but for
+ // that a subpixel image size is rounded to empty, to avoid infinite tile
+ // scale that would be calculated in the |else| part.
+ // We should probably support subpixel size here.
+ intrinsic_tile_size.IsEmpty()) {
intrinsic_tile_size = tile_size;
} else {
scale = FloatSize(tile_size.Width() / intrinsic_tile_size.Width(),
@@ -412,26 +443,48 @@ void DrawTiledBackground(GraphicsContext& context,
if (one_tile_rect.Contains(dest_rect_for_subset)) {
FloatRect visible_src_rect = ComputeSubsetForBackground(
one_tile_rect, dest_rect_for_subset, intrinsic_tile_size);
- // Round to avoid filtering pulling in neighboring pixels, for the
- // common case of sprite maps.
- // TODO(schenney): Snapping at this level is a problem for cases where we
- // might be animating background-position to pan over an image. Ideally we
- // would either snap only if close to integral, or move snapping
- // calculations up the stack.
- visible_src_rect = FloatRect(RoundedIntRect(visible_src_rect));
+ visible_src_rect = SnapSourceRectIfNearIntegral(visible_src_rect);
+
+ // When respecting image orientation, the drawing code expects the source
+ // rect to be in the unrotated image space, but we have computed it here in
+ // the rotated space in order to position and size the background. Undo the
+ // src rect rotation if necessary.
+ if (respect_orientation && !image->HasDefaultOrientation()) {
+ visible_src_rect = image->CorrectSrcRectForImageOrientation(
+ visible_src_rect.Size(), visible_src_rect);
+ }
+
context.DrawImage(image, Image::kSyncDecode, snapped_paint_rect,
&visible_src_rect, has_filter_property, op,
- kDoNotRespectImageOrientation);
+ respect_orientation);
return;
}
+ // At this point we have decided to tile the image to fill the dest rect.
// Note that this tile rect the image's pre-scaled size.
FloatRect tile_rect(FloatPoint(), intrinsic_tile_size);
+
+ // Farther down the pipeline we will use the scaled tile size to determine
+ // which dimensions to clamp or repeat in. We do not want to repeat when the
+ // tile size rounds to match the dest in a given dimension, to avoid having
+ // a single row or column repeated when the developer almost certainly
+ // intended the image to not repeat (this generally occurs under zoom).
+ //
+ // So detect when we do not want to repeat and set the scale to round the
+ // values in that dimension.
+ if (fabs(tile_size.Width() - snapped_paint_rect.Width()) <= 0.5) {
+ scale.SetWidth(snapped_paint_rect.Width() / intrinsic_tile_size.Width());
+ }
+ if (fabs(tile_size.Height() - snapped_paint_rect.Height()) <= 0.5) {
+ scale.SetHeight(snapped_paint_rect.Height() / intrinsic_tile_size.Height());
+ }
+
// This call takes the unscaled image, applies the given scale, and paints
// it into the snapped_dest_rect using phase from one_tile_rect and the
// given repeat spacing. Note the phase is already scaled.
context.DrawImageTiled(image, snapped_paint_rect, tile_rect, scale,
- one_tile_rect.Location(), repeat_spacing, op);
+ one_tile_rect.Location(), repeat_spacing, op,
+ respect_orientation);
}
inline bool PaintFastBottomLayer(Node* node,
@@ -528,7 +581,10 @@ inline bool PaintFastBottomLayer(Node* node,
// intrinsic size is the requested tile size.
bool has_intrinsic_size = image->HasIntrinsicSize();
const FloatSize intrinsic_tile_size =
- !has_intrinsic_size ? image_tile.Size() : FloatSize(image->Size());
+ !has_intrinsic_size
+ ? image_tile.Size()
+ : FloatSize(image->Size(info.respect_image_orientation));
+
// Subset computation needs the same location as was used with
// ComputePhaseForBackground above, but needs the unsnapped destination
// size to correctly calculate sprite subsets in the presence of zoom. But if
@@ -544,12 +600,21 @@ inline bool PaintFastBottomLayer(Node* node,
// from integer size, so it is safe to round without introducing major issues.
const FloatRect unrounded_subset = ComputeSubsetForBackground(
image_tile, dest_rect_for_subset, intrinsic_tile_size);
- FloatRect src_rect = FloatRect(RoundedIntRect(unrounded_subset));
+ FloatRect src_rect = SnapSourceRectIfNearIntegral(unrounded_subset);
- // If we have rounded the image size to 0, revert the rounding.
+ // If we have snapped the image size to 0, revert the rounding.
if (src_rect.IsEmpty())
src_rect = unrounded_subset;
+ // When respecting image orientation, the drawing code expects the source rect
+ // to be in the unrotated image space, but we have computed it here in the
+ // rotated space in order to position and size the background. Undo the src
+ // rect rotation if necessaary.
+ if (info.respect_image_orientation && !image->HasDefaultOrientation()) {
+ src_rect =
+ image->CorrectSrcRectForImageOrientation(src_rect.Size(), src_rect);
+ }
+
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage",
"data",
inspector_paint_image_event::Data(
@@ -561,19 +626,21 @@ inline bool PaintFastBottomLayer(Node* node,
context.DrawImageRRect(
image, Image::kSyncDecode, image_border, src_rect,
node && node->ComputedStyleRef().HasFilterInducingProperty(),
- composite_op);
+ composite_op, info.respect_image_orientation);
if (info.image && info.image->IsImageResource()) {
PaintTimingDetector::NotifyBackgroundImagePaint(
- node, image, To<StyleFetchedImage>(info.image.Get()),
- paint_info.context.GetPaintController().CurrentPaintChunkProperties());
+ node, image, To<StyleFetchedImage>(info.image),
+ paint_info.context.GetPaintController().CurrentPaintChunkProperties(),
+ RoundedIntRect(image_border.Rect()));
}
if (node && info.image && info.image->IsImageResource()) {
LocalDOMWindow* window = node->GetDocument().domWindow();
DCHECK(window);
ImageElementTiming::From(*window).NotifyBackgroundImagePainted(
- node, To<StyleFetchedImage>(info.image.Get()),
- context.GetPaintController().CurrentPaintChunkProperties());
+ node, To<StyleFetchedImage>(info.image),
+ context.GetPaintController().CurrentPaintChunkProperties(),
+ RoundedIntRect(image_border.Rect()));
}
return true;
}
@@ -691,18 +758,21 @@ void PaintFillLayerBackground(GraphicsContext& context,
FloatRect(geometry.SnappedDestRect()), geometry.Phase(),
FloatSize(geometry.TileSize()), composite_op,
FloatSize(geometry.SpaceSize()),
- node && node->ComputedStyleRef().HasFilterInducingProperty());
+ node && node->ComputedStyleRef().HasFilterInducingProperty(),
+ info.respect_image_orientation);
if (info.image && info.image->IsImageResource()) {
PaintTimingDetector::NotifyBackgroundImagePaint(
- node, image, To<StyleFetchedImage>(info.image.Get()),
- context.GetPaintController().CurrentPaintChunkProperties());
+ node, image, To<StyleFetchedImage>(info.image),
+ context.GetPaintController().CurrentPaintChunkProperties(),
+ EnclosingIntRect(geometry.SnappedDestRect()));
}
if (node && info.image && info.image->IsImageResource()) {
LocalDOMWindow* window = node->GetDocument().domWindow();
DCHECK(window);
ImageElementTiming::From(*window).NotifyBackgroundImagePainted(
- node, To<StyleFetchedImage>(info.image.Get()),
- context.GetPaintController().CurrentPaintChunkProperties());
+ node, To<StyleFetchedImage>(info.image),
+ context.GetPaintController().CurrentPaintChunkProperties(),
+ EnclosingIntRect(geometry.SnappedDestRect()));
}
}
}
@@ -743,7 +813,9 @@ void BoxPainterBase::PaintFillLayer(const PaintInfo& paint_info,
if (rect.IsEmpty())
return;
- const FillLayerInfo info = GetFillLayerInfo(color, bg_layer, bleed_avoidance);
+ const FillLayerInfo info =
+ GetFillLayerInfo(color, bg_layer, bleed_avoidance,
+ IsPaintingScrollingBackground(paint_info));
// If we're not actually going to paint anything, abort early.
if (!info.should_paint_image && !info.should_paint_color)
return;
@@ -913,4 +985,31 @@ void BoxPainterBase::PaintMaskImages(const PaintInfo& paint_info,
include_logical_right_edge);
}
+bool BoxPainterBase::ShouldSkipPaintUnderInvalidationChecking(
+ const LayoutBox& box) {
+ DCHECK(RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled());
+
+ // Disable paint under-invalidation checking for cases that under-invalidation
+ // is intensional and/or harmless.
+
+ // A box having delayed-invalidation may change before it's actually
+ // invalidated. Note that we still report harmless under-invalidation of
+ // non-delayed-invalidation animated background, which should be ignored.
+ if (box.ShouldDelayFullPaintInvalidation())
+ return true;
+
+ // We always paint a MediaSliderPart using the latest data (buffered ranges,
+ // current time and duration) which may be different from the cached data.
+ if (box.StyleRef().EffectiveAppearance() == kMediaSliderPart)
+ return true;
+
+ // We paint an indeterminate progress based on the position calculated from
+ // the animation progress. Harmless under-invalidatoin may happen during a
+ // paint that is not scheduled for animation.
+ if (box.IsProgress() && !ToLayoutProgress(box).IsDeterminate())
+ return true;
+
+ return false;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_base.h b/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
index 146d65ceb78..7b5bbf22c58 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_base.h
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/style/style_image.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
+#include "third_party/blink/renderer/platform/graphics/image_orientation.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/skia/include/core/SkBlendMode.h"
@@ -23,6 +24,7 @@ class FloatRoundedRect;
class GraphicsContext;
class ImageResourceObserver;
class IntRect;
+class LayoutBox;
struct PaintInfo;
struct PhysicalOffset;
struct PhysicalRect;
@@ -102,6 +104,8 @@ class BoxPainterBase {
FillLayerOcclusionOutputList& reversed_paint_list,
const FillLayer&);
+ static bool ShouldSkipPaintUnderInvalidationChecking(const LayoutBox&);
+
struct FillLayerInfo {
STACK_ALLOCATED();
@@ -112,16 +116,19 @@ class BoxPainterBase {
Color bg_color,
const FillLayer&,
BackgroundBleedAvoidance,
+ RespectImageOrientationEnum,
bool include_left_edge,
bool include_right_edge,
- bool is_inline);
+ bool is_inline,
+ bool is_painting_scrolling_background);
// FillLayerInfo is a temporary, stack-allocated container which cannot
// outlive the StyleImage. This would normally be a raw pointer, if not for
// the Oilpan tooling complaints.
- Member<StyleImage> image;
+ StyleImage* image;
Color color;
+ RespectImageOrientationEnum respect_image_orientation;
bool include_left_edge;
bool include_right_edge;
bool is_bottom_layer;
@@ -152,9 +159,12 @@ class BoxPainterBase {
virtual PhysicalRect AdjustRectForScrolledContent(const PaintInfo&,
const FillLayerInfo&,
const PhysicalRect&) = 0;
- virtual FillLayerInfo GetFillLayerInfo(const Color&,
- const FillLayer&,
- BackgroundBleedAvoidance) const = 0;
+ virtual FillLayerInfo GetFillLayerInfo(
+ const Color&,
+ const FillLayer&,
+ BackgroundBleedAvoidance,
+ bool is_painting_scrolling_background) const = 0;
+ virtual bool IsPaintingScrollingBackground(const PaintInfo&) const = 0;
static void PaintInsetBoxShadow(const PaintInfo&,
const FloatRoundedRect&,
const ComputedStyle&,
@@ -162,9 +172,9 @@ class BoxPainterBase {
bool include_logical_right_edge = true);
private:
- Member<const Document> document_;
+ const Document* document_;
const ComputedStyle& style_;
- Member<Node> node_;
+ Node* node_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/box_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/box_painter_test.cc
index d651e69e97d..5a929df6094 100644
--- a/chromium/third_party/blink/renderer/core/paint/box_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/box_painter_test.cc
@@ -7,7 +7,6 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h"
using testing::ElementsAre;
@@ -17,30 +16,50 @@ using BoxPainterTest = PaintControllerPaintTest;
INSTANTIATE_PAINT_TEST_SUITE_P(BoxPainterTest);
-TEST_P(BoxPainterTest, DontPaintEmptyDecorationBackground) {
+TEST_P(BoxPainterTest, EmptyDecorationBackground) {
SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ /* to force a subsequene and paint chunk */
+ opacity: 0.5;
+ /* to verify child empty backgrounds expand chunk bounds */
+ height: 0;
+ }
+ </style>
<div id="div1" style="width: 100px; height: 100px; background: green">
</div>
<div id="div2" style="width: 100px; height: 100px; outline: 2px solid blue">
</div>
+ <div id="div3" style="width: 200px; height: 150px"></div>
)HTML");
auto* div1 = GetLayoutObjectByElementId("div1");
auto* div2 = GetLayoutObjectByElementId("div2");
+ auto* body = GetDocument().body()->GetLayoutBox();
+ // Empty backgrounds don't generate display items.
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
IsSameId(div1, kBackgroundType),
IsSameId(div2, DisplayItem::PaintPhaseToDrawingType(
PaintPhase::kSelfOutlineOnly))));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties(),
+ nullptr, IntRect(0, 0, 800, 600)),
+ // Empty backgrounds contribute to bounds of paint chunks.
+ IsPaintChunk(1, 3,
+ PaintChunk::Id(*body->Layer(), DisplayItem::kLayerChunk),
+ body->FirstFragment().LocalBorderBoxProperties(),
+ nullptr, IntRect(-2, 0, 202, 350))));
}
-using BoxPainterScrollHitTestTest = PaintControllerPaintTest;
-
-INSTANTIATE_SCROLL_HIT_TEST_SUITE_P(BoxPainterScrollHitTestTest);
-
-TEST_P(BoxPainterScrollHitTestTest,
- ScrollHitTestOrderWithScrollBackgroundAttachment) {
+TEST_P(BoxPainterTest, ScrollHitTestOrderWithScrollBackgroundAttachment) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
@@ -60,7 +79,7 @@ TEST_P(BoxPainterScrollHitTestTest,
</div>
)HTML");
- auto& container = *GetLayoutObjectByElementId("container");
+ auto& container = ToLayoutBox(*GetLayoutObjectByElementId("container"));
auto& child = *GetLayoutObjectByElementId("child");
// As a reminder, "background-attachment: scroll" does not move when the
@@ -74,11 +93,29 @@ TEST_P(BoxPainterScrollHitTestTest,
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
IsSameId(&container, kBackgroundType),
- IsSameId(&container, kScrollHitTestType),
IsSameId(&child, kBackgroundType)));
+ HitTestData scroll_hit_test;
+ scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(2, 2,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(2, 3)));
} else {
- // Because the frame composited scrolls, no scroll hit test display item is
- // needed.
+ // Because the frame composited scrolls, no scroll hit test is needed.
const auto* non_scrolling_layer = To<LayoutBlock>(container)
.Layer()
->GetCompositedLayerMapping()
@@ -94,8 +131,7 @@ TEST_P(BoxPainterScrollHitTestTest,
}
}
-TEST_P(BoxPainterScrollHitTestTest,
- ScrollHitTestOrderWithLocalBackgroundAttachment) {
+TEST_P(BoxPainterTest, ScrollHitTestOrderWithLocalBackgroundAttachment) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
@@ -131,12 +167,32 @@ TEST_P(BoxPainterScrollHitTestTest,
RootPaintController().GetDisplayItemList(),
ElementsAre(
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
- IsSameId(&container, kScrollHitTestType),
IsSameId(container_scrolling_client, kBackgroundType),
IsSameId(&child, kBackgroundType)));
+ HitTestData scroll_hit_test;
+ scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(1, 1,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 1, 3, PaintChunk::Id(container, kScrollingBackgroundChunkType),
+ container.FirstFragment().ContentsProperties())));
} else {
- // Because the frame composited scrolls, no scroll hit test display item is
- // needed.
+ // Because the frame composited scrolls, no scroll hit test is needed.
const auto* non_scrolling_layer =
container.Layer()->GetCompositedLayerMapping()->MainGraphicsLayer();
EXPECT_TRUE(non_scrolling_layer->GetPaintController()
@@ -152,12 +208,7 @@ TEST_P(BoxPainterScrollHitTestTest,
}
}
-TEST_P(BoxPainterScrollHitTestTest, ScrollHitTestProperties) {
- // This test depends on the CompositeAfterPaint behavior of painting solid
- // color backgrounds into both the non-scrolled and scrolled spaces.
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
+TEST_P(BoxPainterTest, ScrollHitTestProperties) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar { display: none; }
@@ -183,23 +234,22 @@ TEST_P(BoxPainterScrollHitTestTest, ScrollHitTestProperties) {
// scrolled contents.
EXPECT_EQ(
kBackgroundPaintInGraphicsLayer | kBackgroundPaintInScrollingContents,
- container.GetBackgroundPaintLocation());
+ container.ComputeBackgroundPaintLocationIfComposited());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
+ container.GetBackgroundPaintLocation());
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(&container, kBackgroundType),
- IsSameId(&container, kScrollHitTestType),
- IsSameId(&container.GetScrollableArea()
- ->GetScrollingBackgroundDisplayItemClient(),
- kBackgroundType),
IsSameId(&child, kBackgroundType)));
HitTestData scroll_hit_test_data;
const auto& scrolling_contents_properties =
container.FirstFragment().ContentsProperties();
- scroll_hit_test_data.SetScrollHitTest(
- &scrolling_contents_properties.Transform(), IntRect(0, 0, 200, 200));
+ scroll_hit_test_data.scroll_translation =
+ &scrolling_contents_properties.Transform();
+ scroll_hit_test_data.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
EXPECT_THAT(
paint_chunks,
ElementsAre(
@@ -207,16 +257,18 @@ TEST_P(BoxPainterScrollHitTestTest, ScrollHitTestProperties) {
PaintChunk::Id(ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
GetLayoutView().FirstFragment().ContentsProperties()),
- IsPaintChunk(1, 2,
- PaintChunk::Id(*container.Layer(),
- kNonScrollingBackgroundChunkType),
- container.FirstFragment().LocalBorderBoxProperties()),
- IsPaintChunk(2, 3, PaintChunk::Id(container, kScrollHitTestType),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(2, 2,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
container.FirstFragment().LocalBorderBoxProperties(),
- scroll_hit_test_data),
- IsPaintChunk(3, 5,
- PaintChunk::Id(container, kScrollingBackgroundChunkType),
- scrolling_contents_properties)));
+ &scroll_hit_test_data, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 2, 3,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ scrolling_contents_properties)));
// We always create scroll node for the root layer.
const auto& root_transform = paint_chunks[0].properties.Transform();
@@ -237,25 +289,23 @@ TEST_P(BoxPainterScrollHitTestTest, ScrollHitTestProperties) {
EXPECT_EQ(nullptr, scroll_hit_test_transform.ScrollNode());
EXPECT_EQ(&root_transform, scroll_hit_test_transform.Parent());
const auto& scroll_hit_test_clip = scroll_hit_test_chunk.properties.Clip();
- EXPECT_EQ(FloatRect(0, 0, 800, 600), scroll_hit_test_clip.ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 800, 600),
+ scroll_hit_test_clip.UnsnappedClipRect().Rect());
// The scrolled contents should be scrolled and clipped.
- const auto& contents_chunk = RootPaintController().PaintChunks()[3];
+ const auto& contents_chunk = paint_chunks[3];
const auto& contents_transform = contents_chunk.properties.Transform();
const auto* contents_scroll = contents_transform.ScrollNode();
EXPECT_EQ(IntSize(200, 300), contents_scroll->ContentsSize());
EXPECT_EQ(IntRect(0, 0, 200, 200), contents_scroll->ContainerRect());
const auto& contents_clip = contents_chunk.properties.Clip();
- EXPECT_EQ(FloatRect(0, 0, 200, 200), contents_clip.ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 200, 200),
+ contents_clip.UnsnappedClipRect().Rect());
- // The scroll hit test display item maintains a reference to a scroll offset
- // translation node and the contents should be scrolled by this node.
- const auto& scroll_hit_test_display_item =
- static_cast<const ScrollHitTestDisplayItem&>(
- RootPaintController()
- .GetDisplayItemList()[scroll_hit_test_chunk.begin_index]);
+ // The scroll paint chunk maintains a reference to a scroll translation node
+ // and the contents should be scrolled by this node.
EXPECT_EQ(&contents_transform,
- scroll_hit_test_display_item.scroll_offset_node());
+ scroll_hit_test_chunk.hit_test_data->scroll_translation);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index 9e1eed19de9..2091d948454 100644
--- a/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -25,22 +25,6 @@ namespace blink {
namespace {
-class SVGClipExpansionCycleHelper {
- public:
- void Lock(LayoutSVGResourceClipper& clipper) {
- DCHECK(!clipper.HasCycle());
- clipper.BeginClipExpansion();
- clippers_.push_back(&clipper);
- }
- ~SVGClipExpansionCycleHelper() {
- for (auto* clipper : clippers_)
- clipper->EndClipExpansion();
- }
-
- private:
- Vector<LayoutSVGResourceClipper*, 1> clippers_;
-};
-
LayoutSVGResourceClipper* ResolveElementReference(
const LayoutObject& layout_object,
const ReferenceClipPathOperation& reference_clip_path_operation) {
@@ -65,7 +49,7 @@ LayoutSVGResourceClipper* ResolveElementReference(
FloatRect ClipPathClipper::LocalReferenceBox(const LayoutObject& object) {
if (object.IsSVGChild())
- return object.ObjectBoundingBox();
+ return SVGResources::ReferenceBoxForEffects(object);
if (object.IsBox())
return FloatRect(ToLayoutBox(object).BorderBoxRect());
@@ -127,17 +111,17 @@ static bool IsClipPathOperationValid(
return false;
SECURITY_DCHECK(!resource_clipper->NeedsLayout());
resource_clipper->ClearInvalidationMask();
- if (resource_clipper->HasCycle())
- return false;
}
return true;
}
ClipPathClipper::ClipPathClipper(GraphicsContext& context,
const LayoutObject& layout_object,
+ const DisplayItemClient& display_item_client,
const PhysicalOffset& paint_offset)
: context_(context),
layout_object_(layout_object),
+ display_item_client_(display_item_client),
paint_offset_(paint_offset) {
DCHECK(layout_object.StyleRef().ClipPath());
}
@@ -166,20 +150,20 @@ ClipPathClipper::~ClipPathClipper() {
return;
ScopedPaintChunkProperties scoped_properties(
context_.GetPaintController(),
- layout_object_.FirstFragment().ClipPathProperties(), layout_object_,
+ layout_object_.FirstFragment().ClipPathProperties(), display_item_client_,
DisplayItem::kSVGClip);
bool is_svg_child = layout_object_.IsSVGChild();
FloatRect reference_box = LocalReferenceBox(layout_object_);
- if (DrawingRecorder::UseCachedDrawingIfPossible(context_, layout_object_,
- DisplayItem::kSVGClip))
+ if (DrawingRecorder::UseCachedDrawingIfPossible(
+ context_, display_item_client_, DisplayItem::kSVGClip))
return;
- DrawingRecorder recorder(context_, layout_object_, DisplayItem::kSVGClip);
+ DrawingRecorder recorder(context_, display_item_client_,
+ DisplayItem::kSVGClip);
context_.Save();
context_.Translate(paint_offset_.left, paint_offset_.top);
- SVGClipExpansionCycleHelper locks;
bool is_first = true;
bool rest_of_the_chain_already_appled = false;
const LayoutObject* current_object = &layout_object_;
@@ -201,7 +185,6 @@ ClipPathClipper::~ClipPathClipper() {
// because it would have been applied as path-based clip already.
DCHECK(resource_clipper);
DCHECK_EQ(clip_path->GetType(), ClipPathOperation::REFERENCE);
- locks.Lock(*resource_clipper);
if (resource_clipper->StyleRef().ClipPath()) {
// Try to apply nested clip-path as path-based clip.
bool unused;
diff --git a/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.h b/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.h
index c852040eb9a..a52caedba03 100644
--- a/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.h
+++ b/chromium/third_party/blink/renderer/core/paint/clip_path_clipper.h
@@ -13,6 +13,7 @@
namespace blink {
+class DisplayItemClient;
class GraphicsContext;
class LayoutObject;
@@ -22,6 +23,7 @@ class CORE_EXPORT ClipPathClipper {
public:
ClipPathClipper(GraphicsContext&,
const LayoutObject&,
+ const DisplayItemClient&,
const PhysicalOffset& paint_offset);
~ClipPathClipper();
@@ -52,6 +54,7 @@ class CORE_EXPORT ClipPathClipper {
private:
GraphicsContext& context_;
const LayoutObject& layout_object_;
+ const DisplayItemClient& display_item_client_;
PhysicalOffset paint_offset_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 0927a3d005f..4a32393fafc 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -28,7 +28,6 @@
#include <memory>
#include "cc/layers/picture_layer.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/accessibility/apply_dark_mode.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
@@ -45,6 +44,7 @@
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
+#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_object.h"
#include "third_party/blink/renderer/core/layout/layout_html_canvas.h"
@@ -180,7 +180,7 @@ static bool NeedsDecorationOutlineLayer(const PaintLayer& paint_layer,
bool could_obscure_decorations =
(paint_layer.GetScrollableArea() &&
paint_layer.GetScrollableArea()->UsesCompositedScrolling()) ||
- layout_object.IsCanvas() || layout_object.IsVideo();
+ layout_object.IsCanvas() || IsA<LayoutVideo>(layout_object);
return could_obscure_decorations && layout_object.StyleRef().HasOutline() &&
layout_object.StyleRef().OutlineOffset() < -min_border_width;
@@ -189,21 +189,12 @@ static bool NeedsDecorationOutlineLayer(const PaintLayer& paint_layer,
CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
: owning_layer_(layer),
pending_update_scope_(kGraphicsLayerUpdateNone),
- is_main_frame_layout_view_layer_(false),
scrolling_contents_are_empty_(false),
- background_paints_onto_scrolling_contents_layer_(false),
- background_paints_onto_graphics_layer_(false),
draws_background_onto_content_layer_(false) {
- if (layer.IsRootLayer() && GetLayoutObject().GetFrame()->IsMainFrame())
- is_main_frame_layout_view_layer_ = true;
-
CreatePrimaryGraphicsLayer();
}
CompositedLayerMapping::~CompositedLayerMapping() {
- // Hits in compositing/squashing/squash-onto-nephew.html.
- DisableCompositingQueryAsserts disabler;
-
// Do not leave the destroyed pointer dangling on any Layers that painted to
// this mapping's squashing layer.
for (wtf_size_t i = 0; i < squashed_layers_.size(); ++i) {
@@ -222,7 +213,6 @@ CompositedLayerMapping::~CompositedLayerMapping() {
UpdateMaskLayer(false);
UpdateScrollingLayers(false);
UpdateSquashingLayers(false);
- DestroyGraphicsLayers();
}
std::unique_ptr<GraphicsLayer> CompositedLayerMapping::CreateGraphicsLayer(
@@ -237,6 +227,26 @@ std::unique_ptr<GraphicsLayer> CompositedLayerMapping::CreateGraphicsLayer(
static_cast<int>(DOMNodeIds::IdForNode(owning_node)));
}
+ // Attempt to associate each layer with the frame owner's element ID.
+ Document* owner = nullptr;
+ if (GetLayoutObject().IsLayoutEmbeddedContent()) {
+ auto& embedded = ToLayoutEmbeddedContent(GetLayoutObject());
+ if (auto* frame_view =
+ DynamicTo<LocalFrameView>(embedded.GetEmbeddedContentView())) {
+ owner = frame_view->GetFrame().GetDocument();
+ } else {
+ // Ignore remote and plugin frames.
+ }
+ } else {
+ owner = &GetLayoutObject().GetDocument();
+ }
+ if (owner) {
+ graphics_layer->CcLayer()->SetFrameElementId(
+ CompositorElementIdFromUniqueObjectId(
+ DOMNodeIds::IdForNode(owner),
+ CompositorElementIdNamespace::kDOMNodeId));
+ }
+
return graphics_layer;
}
@@ -248,52 +258,6 @@ void CompositedLayerMapping::CreatePrimaryGraphicsLayer() {
graphics_layer_->SetHitTestable(true);
}
-void CompositedLayerMapping::DestroyGraphicsLayers() {
- if (graphics_layer_)
- graphics_layer_->RemoveFromParent();
-
- graphics_layer_ = nullptr;
- foreground_layer_ = nullptr;
- mask_layer_ = nullptr;
-
- scrolling_layer_ = nullptr;
- scrolling_contents_layer_ = nullptr;
-}
-
-void CompositedLayerMapping::UpdateBackgroundPaintsOntoScrollingContentsLayer(
- bool& invalidate_graphics_layer,
- bool& invalidate_scrolling_contents_layer) {
- invalidate_graphics_layer = false;
- invalidate_scrolling_contents_layer = false;
- // We can only paint the background onto the scrolling contents layer if
- // it would be visually correct and we are using composited scrolling meaning
- // we have a scrolling contents layer to paint it into.
- BackgroundPaintLocation paint_location =
- GetLayoutObject().GetBackgroundPaintLocation();
- bool should_paint_onto_scrolling_contents_layer =
- paint_location & kBackgroundPaintInScrollingContents &&
- owning_layer_.GetScrollableArea()->UsesCompositedScrolling();
- if (should_paint_onto_scrolling_contents_layer !=
- BackgroundPaintsOntoScrollingContentsLayer()) {
- background_paints_onto_scrolling_contents_layer_ =
- should_paint_onto_scrolling_contents_layer;
- // The scrolling contents layer needs to be updated for changed
- // m_backgroundPaintsOntoScrollingContentsLayer.
- if (HasScrollingLayer())
- invalidate_scrolling_contents_layer = true;
- }
- bool should_paint_onto_graphics_layer =
- !background_paints_onto_scrolling_contents_layer_ ||
- paint_location & kBackgroundPaintInGraphicsLayer;
- if (should_paint_onto_graphics_layer !=
- !!background_paints_onto_graphics_layer_) {
- background_paints_onto_graphics_layer_ = should_paint_onto_graphics_layer;
- // The graphics layer needs to be updated for changed
- // m_backgroundPaintsOntoGraphicsLayer.
- invalidate_graphics_layer = true;
- }
-}
-
void CompositedLayerMapping::UpdateContentsOpaque() {
// If there is a foreground layer, children paint into that layer and
// not graphics_layer_, and so don't contribute to the opaqueness of the
@@ -322,40 +286,35 @@ void CompositedLayerMapping::UpdateContentsOpaque() {
// TODO(crbug.com/705019): Contents could be opaque, but that cannot be
// determined from the main thread. Or can it?
graphics_layer_->SetContentsOpaque(false);
- } else {
- // For non-root layers, background is painted by the scrolling contents
- // layer if all backgrounds are background attachment local, otherwise
- // background is painted by the primary graphics layer.
- if (HasScrollingLayer() &&
- background_paints_onto_scrolling_contents_layer_) {
- // Backgrounds painted onto the foreground are clipped by the padding box
- // rect.
- // TODO(flackr): This should actually check the entire overflow rect
- // within the scrolling contents layer but since we currently only trigger
- // this for solid color backgrounds the answer will be the same.
- scrolling_contents_layer_->SetContentsOpaque(
- owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
- ToLayoutBox(GetLayoutObject()).PhysicalPaddingBoxRect(),
- should_check_children));
-
- if (GetLayoutObject().GetBackgroundPaintLocation() &
- kBackgroundPaintInGraphicsLayer) {
- graphics_layer_->SetContentsOpaque(
- owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
- CompositedBounds(), should_check_children));
- } else {
- // If we only paint the background onto the scrolling contents layer we
- // are going to leave a hole in the m_graphicsLayer where the background
- // is so it is not opaque.
- graphics_layer_->SetContentsOpaque(false);
- }
- } else {
- if (HasScrollingLayer())
- scrolling_contents_layer_->SetContentsOpaque(false);
+ } else if (BackgroundPaintsOntoScrollingContentsLayer()) {
+ DCHECK(HasScrollingLayer());
+ // Backgrounds painted onto the foreground are clipped by the padding box
+ // rect.
+ // TODO(flackr): This should actually check the entire overflow rect
+ // within the scrolling contents layer but since we currently only trigger
+ // this for solid color backgrounds the answer will be the same.
+ scrolling_contents_layer_->SetContentsOpaque(
+ owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
+ ToLayoutBox(GetLayoutObject()).PhysicalPaddingBoxRect(),
+ should_check_children));
+
+ if (BackgroundPaintsOntoGraphicsLayer()) {
graphics_layer_->SetContentsOpaque(
owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
CompositedBounds(), should_check_children));
+ } else {
+ // If we only paint the background onto the scrolling contents layer we
+ // are going to leave a hole in the m_graphicsLayer where the background
+ // is so it is not opaque.
+ graphics_layer_->SetContentsOpaque(false);
}
+ } else {
+ DCHECK(BackgroundPaintsOntoGraphicsLayer());
+ if (HasScrollingLayer())
+ scrolling_contents_layer_->SetContentsOpaque(false);
+ graphics_layer_->SetContentsOpaque(
+ owning_layer_.BackgroundIsKnownToBeOpaqueInRect(CompositedBounds(),
+ should_check_children));
}
}
@@ -452,36 +411,30 @@ bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
}
}
- if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) {
- graphics_layer_->SetContentsToCcLayer(
- plugin->CcLayer(), plugin->PreventContentsOpaqueChangesToCcLayer());
- } else {
- auto* frame_owner =
- DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode());
- if (frame_owner && frame_owner->ContentFrame()) {
- Frame* frame = frame_owner->ContentFrame();
- if (auto* remote = DynamicTo<RemoteFrame>(frame)) {
- cc::Layer* layer = remote->GetCcLayer();
+ if (layout_object.IsLayoutEmbeddedContent()) {
+ if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) {
+ graphics_layer_->SetContentsToCcLayer(
+ plugin->CcLayer(), plugin->PreventContentsOpaqueChangesToCcLayer());
+ } else if (auto* frame_owner =
+ DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode())) {
+ if (auto* remote = DynamicTo<RemoteFrame>(frame_owner->ContentFrame())) {
graphics_layer_->SetContentsToCcLayer(
- layer, remote->WebLayerHasFixedContentsOpaque());
+ remote->GetCcLayer(), remote->WebLayerHasFixedContentsOpaque());
}
- } else if (layout_object.IsVideo()) {
- HTMLMediaElement* media_element =
- ToHTMLMediaElement(layout_object.GetNode());
- graphics_layer_->SetContentsToCcLayer(
- media_element->CcLayer(),
- /*prevent_contents_opaque_changes=*/true);
- } else if (layout_object.IsCanvas()) {
- graphics_layer_->SetContentsToCcLayer(
- To<HTMLCanvasElement>(layout_object.GetNode())->ContentsCcLayer(),
- /*prevent_contents_opaque_changes=*/false);
- layer_config_changed = true;
}
- }
- if (layout_object.IsLayoutEmbeddedContent()) {
if (PaintLayerCompositor::AttachFrameContentLayersToIframeLayer(
ToLayoutEmbeddedContent(layout_object)))
layer_config_changed = true;
+ } else if (IsA<LayoutVideo>(layout_object)) {
+ auto* media_element = To<HTMLMediaElement>(layout_object.GetNode());
+ graphics_layer_->SetContentsToCcLayer(
+ media_element->CcLayer(),
+ /*prevent_contents_opaque_changes=*/true);
+ } else if (layout_object.IsCanvas()) {
+ graphics_layer_->SetContentsToCcLayer(
+ To<HTMLCanvasElement>(layout_object.GetNode())->ContentsCcLayer(),
+ /*prevent_contents_opaque_changes=*/false);
+ layer_config_changed = true;
}
if (layer_config_changed) {
@@ -769,22 +722,7 @@ void CompositedLayerMapping::UpdateGraphicsLayerGeometry(
UpdateContentsRect();
UpdateBackgroundColor();
-
- bool invalidate_graphics_layer;
- bool invalidate_scrolling_contents_layer;
- UpdateBackgroundPaintsOntoScrollingContentsLayer(
- invalidate_graphics_layer, invalidate_scrolling_contents_layer);
-
- // This depends on background_paints_onto_graphics_layer_.
UpdateDrawsContentAndPaintsHitTest();
-
- // These invalidations need to happen after
- // |UpdateDrawsContentAndPaintsHitTest|.
- if (invalidate_graphics_layer)
- graphics_layer_->SetNeedsDisplay();
- if (invalidate_scrolling_contents_layer)
- scrolling_contents_layer_->SetNeedsDisplay();
-
UpdateElementId();
UpdateContentsOpaque();
UpdateRasterizationPolicy();
@@ -846,11 +784,11 @@ void CompositedLayerMapping::UpdateOverflowControlsHostLayerGeometry(
// To clip the scrollbars correctly, overflow_controls_host_layer_ should
// match our border box size.
- const IntRect border_box =
- owning_layer_.GetLayoutBox()->PixelSnappedBorderBoxRect(
- owning_layer_.SubpixelAccumulation());
- overflow_controls_host_layer_->SetSize(gfx::Size(border_box.Size()));
- overflow_controls_host_layer_->SetMasksToBounds(true);
+ const IntSize border_box_size =
+ owning_layer_.GetLayoutBox()->PixelSnappedBorderBoxSize(
+ PhysicalOffset(owning_layer_.SubpixelAccumulation() +
+ owning_layer_.GetLayoutBox()->PhysicalLocation()));
+ overflow_controls_host_layer_->SetSize(gfx::Size(border_box_size));
}
void CompositedLayerMapping::UpdateMaskLayerGeometry() {
@@ -890,7 +828,8 @@ void CompositedLayerMapping::UpdateScrollingLayerGeometry() {
scroll_size = scroll_size.ExpandedTo(overflow_clip_rect.Size());
auto* scrolling_coordinator = owning_layer_.GetScrollingCoordinator();
- scrolling_coordinator->UpdateCompositedScrollOffset(scrollable_area);
+ scrolling_coordinator->UpdateCompositorScrollOffset(*layout_box.GetFrame(),
+ *scrollable_area);
if (gfx::Size(scroll_size) != scrolling_contents_layer_->Size() ||
scroll_container_size_changed) {
@@ -1028,7 +967,7 @@ void CompositedLayerMapping::UpdateContentsRect() {
void CompositedLayerMapping::UpdateDrawsContentAndPaintsHitTest() {
bool in_overlay_fullscreen_video = false;
- if (GetLayoutObject().IsVideo()) {
+ if (IsA<LayoutVideo>(GetLayoutObject())) {
auto* video_element = To<HTMLVideoElement>(GetLayoutObject().GetNode());
if (video_element->IsFullscreen() &&
video_element->UsesOverlayFullscreenVideo())
@@ -1393,7 +1332,6 @@ bool CompositedLayerMapping::UpdateScrollingLayers(
CreateGraphicsLayer(CompositingReason::kLayerForScrollingContainer);
scrolling_layer_->SetDrawsContent(false);
scrolling_layer_->SetHitTestable(false);
- scrolling_layer_->SetMasksToBounds(true);
// Inner layer which renders the content that scrolls.
scrolling_contents_layer_ =
@@ -1410,8 +1348,8 @@ bool CompositedLayerMapping::UpdateScrollingLayers(
scrolling_coordinator->ScrollableAreaScrollLayerDidChange(
scrollable_area);
const auto& object = GetLayoutObject();
- if (object.IsLayoutView())
- ToLayoutView(object).GetFrameView()->ScrollableAreasDidChange();
+ if (auto* layout_view = DynamicTo<LayoutView>(object))
+ layout_view->GetFrameView()->ScrollableAreasDidChange();
}
}
} else if (scrolling_layer_) {
@@ -1422,8 +1360,8 @@ bool CompositedLayerMapping::UpdateScrollingLayers(
scrolling_coordinator->ScrollableAreaScrollLayerDidChange(
scrollable_area);
const auto& object = GetLayoutObject();
- if (object.IsLayoutView())
- ToLayoutView(object).GetFrameView()->ScrollableAreasDidChange();
+ if (auto* layout_view = DynamicTo<LayoutView>(object))
+ layout_view->GetFrameView()->ScrollableAreasDidChange();
}
}
@@ -1487,8 +1425,9 @@ CompositedLayerMapping::PaintingPhaseForPrimaryLayer() const {
Color CompositedLayerMapping::LayoutObjectBackgroundColor() const {
const auto& object = GetLayoutObject();
auto background_color = object.ResolveColor(GetCSSPropertyBackgroundColor());
- if (object.IsLayoutView() && object.GetDocument().IsInMainFrame()) {
- return ToLayoutView(object).GetFrameView()->BaseBackgroundColor().Blend(
+ auto* layout_view = DynamicTo<LayoutView>(object);
+ if (layout_view && object.GetDocument().IsInMainFrame()) {
+ return layout_view->GetFrameView()->BaseBackgroundColor().Blend(
background_color);
}
return background_color;
@@ -1545,13 +1484,13 @@ bool CompositedLayerMapping::ContainsPaintedContent() const {
// FIXME: we could optimize cases where the image, video or canvas is known to
// fill the border box entirely, and set background color on the layer in that
// case, instead of allocating backing store and painting.
- if (layout_object.IsVideo() &&
- ToLayoutVideo(layout_object).ShouldDisplayVideo())
+ auto* layout_video = DynamicTo<LayoutVideo>(layout_object);
+ if (layout_video && layout_video->ShouldDisplayVideo())
return owning_layer_.HasBoxDecorationsOrBackground();
if (layout_object.GetNode() && layout_object.GetNode()->IsDocumentNode()) {
if (owning_layer_.NeedsCompositedScrolling())
- return background_paints_onto_graphics_layer_;
+ return BackgroundPaintsOntoGraphicsLayer();
// Look to see if the root object has a non-simple background
LayoutObject* root_object =
@@ -1595,9 +1534,6 @@ bool CompositedLayerMapping::ContainsPaintedContent() const {
bool CompositedLayerMapping::IsDirectlyCompositedImage() const {
DCHECK(GetLayoutObject().IsImage());
- if (base::FeatureList::IsEnabled(features::kDisableDirectlyCompositedImages))
- return false;
-
LayoutImage& image_layout_object = ToLayoutImage(GetLayoutObject());
if (owning_layer_.HasBoxDecorationsOrBackground() ||
@@ -1609,8 +1545,7 @@ bool CompositedLayerMapping::IsDirectlyCompositedImage() const {
if (!cached_image->HasImage())
return false;
- Image* image = cached_image->GetImage();
- if (!image->IsBitmapImage())
+ if (!IsA<BitmapImage>(cached_image->GetImage()))
return false;
UseCounter::Count(GetLayoutObject().GetDocument(),
@@ -1944,7 +1879,7 @@ IntRect CompositedLayerMapping::RecomputeInterestRect(
GeometryMapper::LocalToAncestorVisualRect(
source_state, root_view_contents_state, mapping_rect);
- FloatRect visible_content_rect = mapping_rect.Rect();
+ FloatRect visible_content_rect(EnclosingIntRect(mapping_rect.Rect()));
// 3. Move into local border box transform space of the root LayoutView.
// Note that the overflow clip has *not* been applied.
@@ -2175,10 +2110,10 @@ void CompositedLayerMapping::PaintContents(
graphics_layer == mask_layer_.get() ||
graphics_layer == scrolling_contents_layer_.get() ||
graphics_layer == decoration_outline_layer_.get()) {
- if (background_paints_onto_scrolling_contents_layer_) {
+ if (BackgroundPaintsOntoScrollingContentsLayer()) {
if (graphics_layer == scrolling_contents_layer_.get())
paint_layer_flags &= ~kPaintLayerPaintingSkipRootBackground;
- else if (!background_paints_onto_graphics_layer_)
+ else if (!BackgroundPaintsOntoGraphicsLayer())
paint_layer_flags |= kPaintLayerPaintingSkipRootBackground;
}
@@ -2221,12 +2156,12 @@ void CompositedLayerMapping::PaintScrollableArea(
if (graphics_layer == LayerForHorizontalScrollbar()) {
if (const Scrollbar* scrollbar = scrollable_area->HorizontalScrollbar()) {
if (cull_rect.Intersects(scrollbar->FrameRect()))
- scrollbar->Paint(context);
+ scrollbar->Paint(context, IntPoint());
}
} else if (graphics_layer == LayerForVerticalScrollbar()) {
if (const Scrollbar* scrollbar = scrollable_area->VerticalScrollbar()) {
if (cull_rect.Intersects(scrollbar->FrameRect()))
- scrollbar->Paint(context);
+ scrollbar->Paint(context, IntPoint());
}
} else if (graphics_layer == LayerForScrollCorner()) {
ScrollableAreaPainter painter(*scrollable_area);
@@ -2309,33 +2244,6 @@ void CompositedLayerMapping::VerifyNotPainting() {
}
#endif
-// Only used for performance benchmark testing. Intended to be a
-// sufficiently-unique element id name to allow picking out the target element
-// for invalidation.
-static const char kTestPaintInvalidationTargetName[] =
- "blinkPaintInvalidationTarget";
-
-void CompositedLayerMapping::InvalidateTargetElementForTesting() {
- // The below is an artificial construct formed intentionally to focus a
- // microbenchmark on the cost of paint with a partial invalidation.
- Element* target_element =
- owning_layer_.GetLayoutObject().GetDocument().getElementById(
- AtomicString(kTestPaintInvalidationTargetName));
- // TODO(wkorman): If we don't find the expected target element, we could
- // consider walking to the first leaf node so that the partial-invalidation
- // benchmark mode still provides some value when running on generic pages.
- if (!target_element)
- return;
- LayoutObject* target_object = target_element->GetLayoutObject();
- if (!target_object)
- return;
- target_object->EnclosingLayer()->SetNeedsRepaint();
- // TODO(wkorman): Consider revising the below to invalidate all
- // non-compositing descendants as well.
- target_object->InvalidateDisplayItemClients(
- PaintInvalidationReason::kForTesting);
-}
-
bool CompositedLayerMapping::InvalidateLayerIfNoPrecedingEntry(
wtf_size_t index_to_clear) {
PaintLayer* layer_to_remove = squashed_layers_[index_to_clear].paint_layer;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index 4d96ad6ac59..bb399d8b1d5 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -100,12 +100,6 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
const PaintLayer* compositing_container,
Vector<PaintLayer*>& layers_needing_paint_invalidation);
- // Update whether background paints onto scrolling contents layer.
- // Returns (through the reference params) what invalidations are needed.
- void UpdateBackgroundPaintsOntoScrollingContentsLayer(
- bool& invalidate_graphics_layer,
- bool& invalidate_scrolling_contents_layer);
-
// Update whether layer needs blending.
void UpdateContentsOpaque();
@@ -169,7 +163,6 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
void UpdateElementId();
// GraphicsLayerClient interface
- void InvalidateTargetElementForTesting() override;
IntRect ComputeInterestRect(
const GraphicsLayer*,
const IntRect& previous_interest_rect) const override;
@@ -258,27 +251,29 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
bool AdjustForCompositedScrolling(const GraphicsLayer*,
IntSize& offset) const;
+ bool DrawsBackgroundOntoContentLayer() const {
+ return draws_background_onto_content_layer_;
+ }
+
+ private:
// Returns true for layers with scrollable overflow which have a background
// that can be painted into the composited scrolling contents layer (i.e.
// the background can scroll with the content). When the background is also
// opaque this allows us to composite the scroller even on low DPI as we can
// draw with subpixel anti-aliasing.
bool BackgroundPaintsOntoScrollingContentsLayer() const {
- return background_paints_onto_scrolling_contents_layer_;
+ return GetLayoutObject().GetBackgroundPaintLocation() &
+ kBackgroundPaintInScrollingContents;
}
// Returns true if the background paints onto the main graphics layer.
// In some situations, we may paint background on both the main graphics layer
// and the scrolling contents layer.
bool BackgroundPaintsOntoGraphicsLayer() const {
- return background_paints_onto_graphics_layer_;
+ return GetLayoutObject().GetBackgroundPaintLocation() &
+ kBackgroundPaintInGraphicsLayer;
}
- bool DrawsBackgroundOntoContentLayer() const {
- return draws_background_onto_content_layer_;
- }
-
- private:
IntRect RecomputeInterestRect(const GraphicsLayer*) const;
static bool InterestRectChangedEnoughToRepaint(
const IntRect& previous_interest_rect,
@@ -323,7 +318,6 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
void UpdateScrollingLayerGeometry();
void CreatePrimaryGraphicsLayer();
- void DestroyGraphicsLayers();
std::unique_ptr<GraphicsLayer> CreateGraphicsLayer(
CompositingReasons,
@@ -483,19 +477,9 @@ class CORE_EXPORT CompositedLayerMapping final : public GraphicsLayerClient {
PhysicalRect composited_bounds_;
unsigned pending_update_scope_ : 2;
- unsigned is_main_frame_layout_view_layer_ : 1;
unsigned scrolling_contents_are_empty_ : 1;
- // Keep track of whether the background is painted onto the scrolling contents
- // layer for invalidations.
- unsigned background_paints_onto_scrolling_contents_layer_ : 1;
-
- // Solid color border boxes may be painted into both the scrolling contents
- // layer and the graphics layer because the scrolling contents layer is
- // clipped by the padding box.
- unsigned background_paints_onto_graphics_layer_ : 1;
-
bool draws_background_onto_content_layer_;
friend class CompositedLayerMappingTest;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index 311dcbe9b6c..b43664bfed7 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -6,8 +6,13 @@
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/property_tree.h"
+#include "cc/trees/scroll_node.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
@@ -64,7 +69,8 @@ TEST_F(CompositedLayerMappingTest, SubpixelAccumulationChange) {
Element* target = GetDocument().getElementById("target");
target->SetInlineStyleProperty(CSSPropertyID::kLeft, "0.6px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
PaintLayer* paint_layer =
ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
@@ -86,7 +92,8 @@ TEST_F(CompositedLayerMappingTest,
Element* target = GetDocument().getElementById("target");
target->SetInlineStyleProperty(CSSPropertyID::kLeft, "0.6px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
PaintLayer* paint_layer =
ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
@@ -129,7 +136,8 @@ TEST_F(CompositedLayerMappingTest,
Element* target = GetDocument().getElementById("target");
target->SetInlineStyleProperty(CSSPropertyID::kLeft, "0.6px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
PaintLayer* paint_layer =
ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
@@ -181,8 +189,8 @@ TEST_F(CompositedLayerMappingTest, TallCompositedScrolledLayerInterestRect) {
)HTML");
UpdateAllLifecyclePhasesForTest();
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 8000),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 8000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
Element* element = GetDocument().getElementById("target");
@@ -199,8 +207,8 @@ TEST_F(CompositedLayerMappingTest, TallNonCompositedScrolledLayerInterestRect) {
)HTML");
UpdateAllLifecyclePhasesForTest();
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 8000),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 8000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetDocument().GetLayoutView()->Layer();
@@ -239,7 +247,7 @@ TEST_F(CompositedLayerMappingTest, VerticalRightLeftWritingModeDocument) {
UpdateAllLifecyclePhasesForTest();
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(-5000, 0), kProgrammaticScroll);
+ ScrollOffset(-5000, 0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
PaintLayer* paint_layer = GetDocument().GetLayoutView()->Layer();
@@ -410,7 +418,7 @@ TEST_F(CompositedLayerMappingTest, 3D45DegRotatedTallInterestRect) {
PaintLayer* paint_layer =
ToLayoutBoxModelObject(element->GetLayoutObject())->Layer();
ASSERT_TRUE(!!paint_layer->GraphicsLayerBacking());
- EXPECT_EQ(IntRect(0, 0, 200, 6249),
+ EXPECT_EQ(IntRect(0, 0, 200, 6226),
RecomputeInterestRect(paint_layer->GraphicsLayerBacking()));
}
@@ -618,8 +626,8 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
EXPECT_EQ(IntRect(0, 0, 800, 4600),
PreviousInterestRect(root_scrolling_layer));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 300),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 300), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Still use the previous interest rect because the recomputed rect hasn't
// changed enough.
@@ -628,8 +636,8 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
EXPECT_EQ(IntRect(0, 0, 800, 4600),
PreviousInterestRect(root_scrolling_layer));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 600),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 600), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Use recomputed interest rect because it changed enough.
EXPECT_EQ(IntRect(0, 0, 800, 5200),
@@ -637,16 +645,16 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
EXPECT_EQ(IntRect(0, 0, 800, 5200),
PreviousInterestRect(root_scrolling_layer));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 5400),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 5400), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(0, 1400, 800, 8600),
RecomputeInterestRect(root_scrolling_layer));
EXPECT_EQ(IntRect(0, 1400, 800, 8600),
PreviousInterestRect(root_scrolling_layer));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 9000),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 9000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Still use the previous interest rect because it contains the recomputed
// interest rect.
@@ -655,8 +663,8 @@ TEST_F(CompositedLayerMappingTest, InterestRectChangeOnViewportScroll) {
EXPECT_EQ(IntRect(0, 1400, 800, 8600),
PreviousInterestRect(root_scrolling_layer));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 2000),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 2000), mojom::blink::ScrollType::kProgrammatic);
// Use recomputed interest rect because it changed enough.
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(0, 0, 800, 6600),
@@ -856,7 +864,7 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeInScrolledDiv) {
// Scroll 8000 pixels down to move the iframe into view.
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 8000.0), kProgrammaticScroll);
+ ScrollOffset(0.0, 8000.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
Element* target = ChildDocument().getElementById("target");
@@ -887,7 +895,7 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfScrolledIframe) {
// Scroll 7500 pixels down to bring the scrollable area to the bottom.
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 7500.0), kProgrammaticScroll);
+ ScrollOffset(0.0, 7500.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
ASSERT_TRUE(ChildDocument().View()->GetLayoutView()->HasLayer());
@@ -921,7 +929,7 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithContentBoxOffset) {
// Scroll 3000 pixels down to bring the scrollable area to somewhere in the
// middle.
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 3000.0), kProgrammaticScroll);
+ ScrollOffset(0.0, 3000.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
ASSERT_TRUE(ChildDocument().View()->GetLayoutView()->HasLayer());
@@ -963,7 +971,7 @@ TEST_F(CompositedLayerMappingTest, InterestRectOfIframeWithFixedContents) {
EXPECT_EQ(IntRect(1000, 0, 4400, 300), RecomputeInterestRect(graphics_layer));
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 3000.0), kProgrammaticScroll);
+ ScrollOffset(0.0, 3000.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Because the fixed element does not scroll, the interest rect is unchanged.
@@ -989,7 +997,7 @@ TEST_F(CompositedLayerMappingTest, ScrolledFixedPositionInterestRect) {
EXPECT_EQ(IntRect(0, 500, 100, 4030), RecomputeInterestRect(graphics_layer));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 200.0), kProgrammaticScroll);
+ ScrollOffset(0.0, 200.0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Because the fixed element does not scroll, the interest rect is unchanged.
@@ -1142,7 +1150,7 @@ TEST_F(CompositedLayerMappingTest,
const auto* container = ToLayoutBox(GetLayoutObjectByElementId("container"));
EXPECT_EQ(kBackgroundPaintInScrollingContents,
- container->GetBackgroundPaintLocation());
+ container->ComputeBackgroundPaintLocationIfComposited());
// We currently don't use composited scrolling when the container has a
// border-radius so even though we can paint the background onto the scrolling
@@ -1150,7 +1158,8 @@ TEST_F(CompositedLayerMappingTest,
// this case.
const auto* mapping = container->Layer()->GetCompositedLayerMapping();
EXPECT_FALSE(mapping->HasScrollingLayer());
- EXPECT_FALSE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
+ container->GetBackgroundPaintLocation());
}
TEST_F(CompositedLayerMappingTest, StickyPositionMainThreadOffset) {
@@ -1184,7 +1193,8 @@ TEST_F(CompositedLayerMappingTest, StickyPositionMainThreadOffset) {
sticky_layer->SetNeedsCompositingInputsUpdate();
EXPECT_TRUE(sticky_layer->NeedsCompositingInputsUpdate());
- GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling();
+ GetDocument().View()->UpdateLifecycleToCompositingCleanPlusScrolling(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(sticky_layer->NeedsCompositingInputsUpdate());
}
@@ -1412,22 +1422,28 @@ TEST_F(CompositedLayerMappingTest, ScrollingContainerBoundsChange) {
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
cc::Layer* scrolling_layer = scrollable_area->LayerForScrolling();
- EXPECT_EQ(0, scrolling_layer->CurrentScrollOffset().y());
+ auto element_id = scrollable_area->GetScrollElementId();
+ auto& scroll_tree =
+ scrolling_layer->layer_tree_host()->property_trees()->scroll_tree;
+ EXPECT_EQ(0, scroll_tree.current_scroll_offset(element_id).y());
EXPECT_EQ(150, scrolling_layer->bounds().height());
- EXPECT_EQ(100, scrolling_layer->scroll_container_bounds().height());
+ auto* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+ EXPECT_EQ(100, scroll_node->container_bounds.height());
scrollerElement->setScrollTop(300);
scrollerElement->setAttribute(html_names::kStyleAttr, "max-height: 25px;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(50, scrolling_layer->CurrentScrollOffset().y());
+ EXPECT_EQ(50, scroll_tree.current_scroll_offset(element_id).y());
EXPECT_EQ(150, scrolling_layer->bounds().height());
- EXPECT_EQ(25, scrolling_layer->scroll_container_bounds().height());
+ scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+ EXPECT_EQ(25, scroll_node->container_bounds.height());
scrollerElement->setAttribute(html_names::kStyleAttr, "max-height: 300px;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(50, scrolling_layer->CurrentScrollOffset().y());
+ EXPECT_EQ(50, scroll_tree.current_scroll_offset(element_id).y());
EXPECT_EQ(150, scrolling_layer->bounds().height());
- EXPECT_EQ(100, scrolling_layer->scroll_container_bounds().height());
+ scroll_node = scroll_tree.FindNodeFromElementId(element_id);
+ EXPECT_EQ(100, scroll_node->container_bounds.height());
}
TEST_F(CompositedLayerMappingTest, MainFrameLayerBackgroundColor) {
@@ -1515,27 +1531,6 @@ TEST_F(CompositedLayerMappingTest, ScrollLayerSizingSubpixelAccumulation) {
mapping->ScrollingContentsLayer()->Size().height());
}
-TEST_F(CompositedLayerMappingTest, SquashingScroll) {
- SetHtmlInnerHTML(R"HTML(
- <style>
- * { margin: 0 }
- </style>
- <div id=target
- style='width: 200px; height: 200px; position: relative; will-change: transform'></div>
- <div id=squashed
- style='width: 200px; height: 200px; top: -200px; position: relative;'></div>
- <div style='width: 10px; height: 3000px'></div>
- )HTML");
-
- auto* squashed =
- ToLayoutBoxModelObject(GetLayoutObjectByElementId("squashed"))->Layer();
- EXPECT_EQ(kPaintsIntoGroupedBacking, squashed->GetCompositingState());
-
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 25),
- kUserScroll);
- UpdateAllLifecyclePhasesForTest();
-}
-
TEST_F(CompositedLayerMappingTest, SquashingScrollInterestRect) {
SetHtmlInnerHTML(R"HTML(
<style>
@@ -1551,8 +1546,8 @@ TEST_F(CompositedLayerMappingTest, SquashingScrollInterestRect) {
ToLayoutBoxModelObject(GetLayoutObjectByElementId("squashed"))->Layer();
EXPECT_EQ(kPaintsIntoGroupedBacking, squashed->GetCompositingState());
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 5000),
- kUserScroll);
+ GetDocument().View()->LayoutViewport()->ScrollBy(
+ ScrollOffset(0, 5000), mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(0, 1000, 200, 5000),
@@ -1776,13 +1771,101 @@ TEST_F(CompositedLayerMappingTest,
GetDocument()
.getElementById("uncorrelated")
->setAttribute(html_names::kStyleAttr, "width: 200px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(mapping->NeedsRepaint(*vertical_scrollbar_layer));
GetDocument().getElementById("child")->setAttribute(html_names::kStyleAttr,
- "height: 300px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ "height: 50px");
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(mapping->NeedsRepaint(*vertical_scrollbar_layer));
}
+TEST_F(CompositedLayerMappingTest, IsolationClippingContainer) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #hideable {
+ overflow: hidden;
+ height: 10px;
+ }
+ .isolation {
+ contain: style layout;
+ height: 100px;
+ }
+ .squash-container {
+ will-change: transform;
+ }
+ .squashed {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100px;
+ height: 100px;
+ }
+ </style>
+ <div id="hideable">
+ <div class="isolation" id="isolation_a">
+ <div class="squash-container" id="squash_container_a">a</div>
+ <div class="squashed"></div>
+ </div>
+ <div class="isolation">
+ <div class="squash-container">b</div>
+ <div class="squashed"></div>
+ </div>
+ </div>
+ )HTML");
+
+ Element* hideable = GetDocument().getElementById("hideable");
+ hideable->SetInlineStyleProperty(CSSPropertyID::kOverflow, "visible");
+
+ UpdateAllLifecyclePhasesForTest();
+
+ auto* isolation_a = GetDocument().getElementById("isolation_a");
+ auto* isolation_a_object = isolation_a->GetLayoutObject();
+
+ auto* squash_container_a = GetDocument().getElementById("squash_container_a");
+ PaintLayer* squash_container_a_layer =
+ ToLayoutBoxModelObject(squash_container_a->GetLayoutObject())->Layer();
+ EXPECT_EQ(squash_container_a_layer->ClippingContainer(), isolation_a_object);
+}
+
+TEST_F(CompositedLayerMappingTest, FrameAttribution) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='child' style='will-change: transform;'></div>
+ <iframe id='subframe' style='will-change: transform;'></iframe>
+ )HTML");
+
+ UpdateAllLifecyclePhasesForTest();
+
+ // Ensure that we correctly attribute child layers in the main frame to their
+ // containing document.
+ Element* child = GetDocument().getElementById("child");
+ PaintLayer* child_paint_layer =
+ ToLayoutBoxModelObject(child->GetLayoutObject())->Layer();
+ auto* child_layer = child_paint_layer->GraphicsLayerBacking()->CcLayer();
+ EXPECT_TRUE(child_layer->frame_element_id());
+
+ EXPECT_EQ(child_layer->frame_element_id(),
+ CompositorElementIdFromUniqueObjectId(
+ DOMNodeIds::IdForNode(&GetDocument()),
+ CompositorElementIdNamespace::kDOMNodeId));
+
+ // Test that a layerized subframe's element ID is that of its containing
+ // document.
+ auto* subframe =
+ To<HTMLFrameOwnerElement>(GetDocument().getElementById("subframe"));
+ EXPECT_TRUE(subframe);
+ PaintLayer* subframe_paint_layer =
+ ToLayoutBoxModelObject(subframe->GetLayoutObject())->Layer();
+ auto* subframe_layer =
+ subframe_paint_layer->GraphicsLayerBacking()->CcLayer();
+ EXPECT_TRUE(subframe_layer->frame_element_id());
+
+ EXPECT_EQ(subframe_layer->frame_element_id(),
+ CompositorElementIdFromUniqueObjectId(
+ DOMNodeIds::IdForNode(subframe->contentDocument()),
+ CompositorElementIdNamespace::kDOMNodeId));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
index 65440c163bd..d745fb4a8fa 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h"
+#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/layout/layout_block.h"
@@ -48,6 +49,13 @@ void CompositingInputsUpdater::Update() {
UpdateType update_type = kDoNotForceUpdate;
PaintLayer* layer =
compositing_inputs_root_ ? compositing_inputs_root_ : root_layer_;
+
+ if (DisplayLockUtilities::NearestLockedExclusiveAncestor(
+ layer->GetLayoutObject())) {
+ compositing_inputs_root_ = nullptr;
+ return;
+ }
+
CompositingReasons initial_compositing_reasons =
layer->DirectCompositingReasons();
ApplyAncestorInfoToSelfAndAncestorsRecursively(layer, update_type, info);
@@ -219,6 +227,22 @@ void CompositingInputsUpdater::UpdateAncestorInfo(PaintLayer* const layer,
info.enclosing_stacking_composited_layer;
PaintLayer* enclosing_squashing_composited_layer =
info.enclosing_squashing_composited_layer;
+
+ if (layer->NeedsCompositingInputsUpdate()) {
+ if (enclosing_stacking_composited_layer) {
+ enclosing_stacking_composited_layer->GetCompositedLayerMapping()
+ ->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
+ }
+
+ if (enclosing_squashing_composited_layer) {
+ enclosing_squashing_composited_layer->GetCompositedLayerMapping()
+ ->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
+ }
+
+ update_type = kForceUpdate;
+ }
+
+
switch (layer->GetCompositingState()) {
case kNotComposited:
break;
@@ -232,17 +256,19 @@ void CompositingInputsUpdater::UpdateAncestorInfo(PaintLayer* const layer,
break;
}
+ // invalidate again after the switch, in case
+ // enclosing_stacking_composited_layer or
+ // enclosing_squashing_composited_layer was previously null.
if (layer->NeedsCompositingInputsUpdate()) {
if (enclosing_stacking_composited_layer) {
enclosing_stacking_composited_layer->GetCompositedLayerMapping()
->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
}
+
if (enclosing_squashing_composited_layer) {
enclosing_squashing_composited_layer->GetCompositedLayerMapping()
->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
}
-
- update_type = kForceUpdate;
}
if (style.GetPosition() == EPosition::kAbsolute) {
@@ -287,13 +313,13 @@ void CompositingInputsUpdater::UpdateAncestorInfo(PaintLayer* const layer,
// in the sense that they don't scroll along with its in-flow contents.
// However LayoutView does clip them.
if (layout_object.CanContainFixedPositionObjects() &&
- !layout_object.IsLayoutView()) {
+ !IsA<LayoutView>(layout_object)) {
info.clip_chain_parent_for_fixed = layer;
info.escape_clip_to_for_fixed = info.escape_clip_to;
info.scrolling_ancestor_for_fixed = info.scrolling_ancestor;
info.needs_reparent_scroll_for_fixed = info.needs_reparent_scroll;
}
- if (layout_object.IsLayoutView())
+ if (IsA<LayoutView>(layout_object))
info.clip_chain_parent_for_fixed = layer;
// CSS clip affects all descendants, not just containing-block descendants.
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
index 3d43a923ee3..4f66645c2eb 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater_test.cc
@@ -69,7 +69,8 @@ TEST_F(CompositingInputsUpdaterTest,
// Before we update compositing inputs, validate that the current ancestor
// overflow no longer has a scrollable area.
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(sticky->Layer()->AncestorOverflowLayer()->GetScrollableArea());
EXPECT_EQ(sticky->Layer()->AncestorOverflowLayer(), outer_scroller->Layer());
@@ -99,8 +100,8 @@ TEST_F(CompositingInputsUpdaterTest, UnclippedAndClippedRectsUnderScroll) {
LayoutBoxModelObject* target =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"));
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 25),
- kUserScroll);
+ GetDocument().View()->LayoutViewport()->ScrollBy(
+ ScrollOffset(0, 25), mojom::blink::ScrollType::kUser);
GetDocument()
.View()
->GetLayoutView()
@@ -125,8 +126,8 @@ TEST_F(CompositingInputsUpdaterTest,
LayoutBoxModelObject* target =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"));
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 25),
- kUserScroll);
+ GetDocument().View()->LayoutViewport()->ScrollBy(
+ ScrollOffset(0, 25), mojom::blink::ScrollType::kUser);
GetDocument()
.View()
->GetLayoutView()
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
index d31bd3e8a32..81eb11a2ed2 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.cc
@@ -28,6 +28,7 @@
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
#include "third_party/blink/renderer/core/animation/worklet_animation_controller.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
@@ -45,8 +46,6 @@ CompositingLayerAssigner::CompositingLayerAssigner(
PaintLayerCompositor* compositor)
: compositor_(compositor), layers_changed_(false) {}
-CompositingLayerAssigner::~CompositingLayerAssigner() = default;
-
void CompositingLayerAssigner::Assign(
PaintLayer* update_root,
Vector<PaintLayer*>& layers_needing_paint_invalidation) {
@@ -135,8 +134,8 @@ CompositingLayerAssigner::GetReasonsPreventingSquashing(
const PaintLayer& squashing_layer =
squashing_state.most_recent_mapping->OwningLayer();
- if (layer->GetLayoutObject().IsVideo() ||
- squashing_layer.GetLayoutObject().IsVideo())
+ if (IsA<LayoutVideo>(layer->GetLayoutObject()) ||
+ IsA<LayoutVideo>(squashing_layer.GetLayoutObject()))
return SquashingDisallowedReason::kSquashingVideoIsDisallowed;
// Don't squash iframes, frames or plugins.
@@ -164,9 +163,6 @@ CompositingLayerAssigner::GetReasonsPreventingSquashing(
if (layer->ScrollsWithRespectTo(&squashing_layer))
return SquashingDisallowedReason::kScrollsWithRespectToSquashingLayer;
- if (layer->ScrollParent() && layer->HasCompositingDescendant())
- return SquashingDisallowedReason::kScrollChildWithCompositedDescendants;
-
if (layer->OpacityAncestor() != squashing_layer.OpacityAncestor())
return SquashingDisallowedReason::kOpacityAncestorMismatch;
@@ -292,15 +288,6 @@ void CompositingLayerAssigner::AssignLayersToBackingsInternal(
layer, composited_layer_update)) {
layers_needing_paint_invalidation.push_back(layer);
layers_changed_ = true;
- if (ScrollingCoordinator* scrolling_coordinator =
- layer->GetScrollingCoordinator()) {
- if (layer->GetLayoutObject()
- .StyleRef()
- .HasViewportConstrainedPosition()) {
- scrolling_coordinator->FrameViewFixedObjectsDidChange(
- layer->GetLayoutObject().View()->GetFrameView());
- }
- }
}
if (composited_layer_update != kNoCompositingStateChange) {
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.h
index e4e34b370fd..557f55726ee 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_layer_assigner.h
@@ -43,7 +43,6 @@ class CompositingLayerAssigner {
public:
explicit CompositingLayerAssigner(PaintLayerCompositor*);
- ~CompositingLayerAssigner();
void Assign(PaintLayer* update_root,
Vector<PaintLayer*>& layers_needing_paint_invalidation);
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
index 0ee97e10d65..3570a6d184e 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.cc
@@ -4,22 +4,20 @@
#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
-#include "base/feature_list.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/css/css_property_names.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
-#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_body_element.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/public/common/features.h"
-
namespace blink {
CompositingReasons CompositingReasonFinder::DirectReasons(
@@ -70,7 +68,7 @@ CompositingReasonFinder::PotentialCompositingReasonsFromStyle(
if (style.BackfaceVisibility() == EBackfaceVisibility::kHidden)
reasons |= CompositingReason::kBackfaceVisibilityHidden;
- reasons |= CompositingReasonsForAnimation(style);
+ reasons |= CompositingReasonsForAnimation(layout_object);
reasons |= CompositingReasonsForWillChange(style);
// If the implementation of CreatesGroup changes, we need to be aware of that
@@ -106,6 +104,26 @@ CompositingReasonFinder::PotentialCompositingReasonsFromStyle(
return reasons;
}
+static bool ShouldPreferCompositingForLayoutView(
+ const LayoutView& layout_view) {
+ auto has_direct_compositing_reasons = [](const LayoutObject* object) -> bool {
+ return object && CompositingReasonFinder::DirectReasonsForPaintProperties(
+ *object) != CompositingReason::kNone;
+ };
+ if (has_direct_compositing_reasons(
+ layout_view.GetFrame()->OwnerLayoutObject()))
+ return true;
+ if (auto* document_element = layout_view.GetDocument().documentElement()) {
+ if (has_direct_compositing_reasons(document_element->GetLayoutObject()))
+ return true;
+ }
+ if (auto* body = layout_view.GetDocument().FirstBodyElement()) {
+ if (has_direct_compositing_reasons(body->GetLayoutObject()))
+ return true;
+ }
+ return false;
+}
+
CompositingReasons CompositingReasonFinder::DirectReasonsForPaintProperties(
const LayoutObject& object) {
// TODO(wangxianzhu): Don't depend on PaintLayer for CompositeAfterPaint.
@@ -113,7 +131,7 @@ CompositingReasons CompositingReasonFinder::DirectReasonsForPaintProperties(
return CompositingReason::kNone;
const ComputedStyle& style = object.StyleRef();
- auto reasons = CompositingReasonsForAnimation(style) |
+ auto reasons = CompositingReasonsForAnimation(object) |
CompositingReasonsForWillChange(style);
if (RequiresCompositingFor3DTransform(object))
@@ -141,7 +159,15 @@ CompositingReasons CompositingReasonFinder::DirectReasonsForPaintProperties(
if (auto* scrollable_area = layer->GetScrollableArea()) {
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
bool force_prefer_compositing_to_lcd_text =
- reasons != CompositingReason::kNone;
+ reasons != CompositingReason::kNone ||
+ // In CompositeAfterPaint though we don't treat hidden backface as
+ // a direct compositing reason, it's very likely that the object will
+ // be composited, and it also indicates preference of compositing,
+ // so we prefer composited scrolling here.
+ style.BackfaceVisibility() == EBackfaceVisibility::kHidden ||
+ (object.IsLayoutView() &&
+ ShouldPreferCompositingForLayoutView(To<LayoutView>(object)));
+
if (scrollable_area->ComputeNeedsCompositedScrolling(
force_prefer_compositing_to_lcd_text)) {
reasons |= CompositingReason::kOverflowScrolling;
@@ -153,6 +179,9 @@ CompositingReasons CompositingReasonFinder::DirectReasonsForPaintProperties(
}
}
+ if (object.CanHaveAdditionalCompositingReasons())
+ reasons |= object.AdditionalCompositingReasons();
+
return reasons;
}
@@ -165,10 +194,8 @@ bool CompositingReasonFinder::RequiresCompositingFor3DTransform(
return false;
// Don't composite "trivial" 3D transforms such as translateZ(0).
- if (Platform::Current()->IsLowEndDevice() ||
- base::FeatureList::IsEnabled(blink::features::kDoNotCompositeTrivial3D)) {
+ if (Platform::Current()->IsLowEndDevice())
return layout_object.StyleRef().HasNonTrivial3DTransformOperation();
- }
return layout_object.StyleRef().Has3DTransformOperation();
}
@@ -202,17 +229,16 @@ CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
// into. These children (the controls) always need to be promoted into their
// own layers to draw on top of the accelerated video.
if (layer.CompositingContainer() &&
- layer.CompositingContainer()->GetLayoutObject().IsVideo())
+ IsA<LayoutVideo>(layer.CompositingContainer()->GetLayoutObject()))
direct_reasons |= CompositingReason::kVideoOverlay;
- const Node* node = layer.GetLayoutObject().GetNode();
-
// Special case for immersive-ar DOM overlay mode, see also
- // PaintLayerCompositor::ApplyXrImmersiveDomOverlayIfNeeded()
- if (node && node->IsElementNode() &&
- node->GetDocument().IsImmersiveArOverlay() &&
- node == Fullscreen::FullscreenElementFrom(node->GetDocument())) {
- direct_reasons |= CompositingReason::kImmersiveArOverlay;
+ // PaintLayerCompositor::GetXrOverlayLayer()
+ if (const Node* node = layer.GetLayoutObject().GetNode()) {
+ if (node->IsElementNode() && node->GetDocument().IsXrOverlay() &&
+ node == Fullscreen::FullscreenElementFrom(node->GetDocument())) {
+ direct_reasons |= CompositingReason::kXrOverlay;
+ }
}
if (layer.IsRootLayer() &&
@@ -221,20 +247,8 @@ CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
direct_reasons |= CompositingReason::kRoot;
}
- // Composite all cross-origin iframes, to improve compositor hit testing for
- // input event targeting. crbug.com/1014273
- if (node && node->IsFrameOwnerElement() &&
- base::FeatureList::IsEnabled(
- blink::features::kCompositeCrossOriginIframes)) {
- if (Frame* iframe_frame = To<HTMLFrameOwnerElement>(node)->ContentFrame()) {
- if (!iframe_frame->GetSecurityContext()->GetSecurityOrigin()->CanAccess(
- node->GetDocument().GetSecurityOrigin())) {
- direct_reasons |= CompositingReason::kCrossOriginIframe;
- }
- }
- }
-
- direct_reasons |= layout_object.AdditionalCompositingReasons();
+ if (layout_object.CanHaveAdditionalCompositingReasons())
+ direct_reasons |= layout_object.AdditionalCompositingReasons();
DCHECK(
!(direct_reasons & CompositingReason::kComboAllStyleDeterminedReasons));
@@ -242,12 +256,15 @@ CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
}
CompositingReasons CompositingReasonFinder::CompositingReasonsForAnimation(
- const ComputedStyle& style) {
+ const LayoutObject& object) {
CompositingReasons reasons = CompositingReason::kNone;
+ const auto& style = object.StyleRef();
if (style.SubtreeWillChangeContents())
return reasons;
- if (style.HasCurrentTransformAnimation())
+ // Transforms don't apply on non-replaced inline elements.
+ // TODO(crbug.com/666244): Support composited transform animation for SVG.
+ if (object.IsBox() && style.HasCurrentTransformAnimation())
reasons |= CompositingReason::kActiveTransformAnimation;
if (style.HasCurrentOpacityAnimation())
reasons |= CompositingReason::kActiveOpacityAnimation;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
index 11e4288a051..212d9ef4c33 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h
@@ -35,8 +35,7 @@ class CORE_EXPORT CompositingReasonFinder {
const LayoutObject&);
static bool RequiresCompositingForScrollableFrame(const LayoutView&);
- static CompositingReasons CompositingReasonsForAnimation(
- const ComputedStyle&);
+ static CompositingReasons CompositingReasonsForAnimation(const LayoutObject&);
static CompositingReasons CompositingReasonsForWillChange(
const ComputedStyle&);
static bool RequiresCompositingFor3DTransform(const LayoutObject&);
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
index 670ba475352..ec556f3f98d 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -23,11 +23,13 @@ class CompositingReasonFinderTest : public RenderingTest {
CompositingReasonFinderTest()
: RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
- private:
+ protected:
void SetUp() override {
EnableCompositing();
RenderingTest::SetUp();
}
+
+ void CheckCompositingReasonsForAnimation(bool supports_transform_animation);
};
TEST_F(CompositingReasonFinderTest, CompositingReasonDependencies) {
@@ -40,42 +42,7 @@ TEST_F(CompositingReasonFinderTest, CompositingReasonDependencies) {
CompositingReason::kComboAllStyleDeterminedReasons);
}
-class CompositingReasonFinderTestWithDoNotCompositeTrivial3D
- : public CompositingReasonFinderTest {
- public:
- CompositingReasonFinderTestWithDoNotCompositeTrivial3D() {
- scoped_feature_list_.InitAndEnableFeature(
- blink::features::kDoNotCompositeTrivial3D);
- }
-
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(CompositingReasonFinderTestWithDoNotCompositeTrivial3D,
- DontPromoteTrivial3D) {
- SetBodyInnerHTML(R"HTML(
- <div id='target'
- style='width: 100px; height: 100px; transform: translateZ(0)'></div>
- )HTML");
-
- Element* target = GetDocument().getElementById("target");
- PaintLayer* paint_layer =
- ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
- EXPECT_EQ(kNotComposited, paint_layer->GetCompositingState());
-}
-
-class CompositingReasonFinderTestWithCompositeTrivial3D
- : public CompositingReasonFinderTest {
- public:
- CompositingReasonFinderTestWithCompositeTrivial3D() {
- scoped_feature_list_.InitAndDisableFeature(
- blink::features::kDoNotCompositeTrivial3D);
- }
-
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(CompositingReasonFinderTestWithCompositeTrivial3D, PromoteTrivial3D) {
+TEST_F(CompositingReasonFinderTest, PromoteTrivial3D) {
SetBodyInnerHTML(R"HTML(
<div id='target'
style='width: 100px; height: 100px; transform: translateZ(0)'></div>
@@ -142,6 +109,42 @@ TEST_F(CompositingReasonFinderTest, OnlyAnchoredStickyPositionPromoted) {
->GetCompositingState());
}
+TEST_F(CompositingReasonFinderTest,
+ OnlyAnchoredStickyPositionPromotedAssumeOverlap) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ blink::features::kAssumeOverlapAfterFixedOrStickyPosition, true);
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .scroller {contain: paint; width: 400px; height: 400px; overflow: auto;
+ will-change: transform;}
+ .sticky { position: sticky; width: 10px; height: 10px;}</style>
+ <div class='scroller'>
+ <div id='sticky-top' class='sticky' style='top: 0px;'></div>
+ <div id='sticky-no-anchor' class='sticky'></div>
+ <div style='height: 2000px;'></div>
+ </div>
+ )HTML");
+
+ EXPECT_EQ(kPaintsIntoOwnBacking,
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky-top"))
+ ->Layer()
+ ->GetCompositingState());
+ // Any scroll dependent layer, such as sticky-top, assumes that it overlaps
+ // anything which draws after it.
+ EXPECT_EQ(
+ kPaintsIntoOwnBacking,
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky-no-anchor"))
+ ->Layer()
+ ->GetCompositingState());
+ EXPECT_EQ(
+ CompositingReason::kAssumedOverlap,
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky-no-anchor"))
+ ->Layer()
+ ->GetCompositingReasons() &
+ CompositingReason::kAssumedOverlap);
+}
+
TEST_F(CompositingReasonFinderTest, OnlyScrollingStickyPositionPromoted) {
SetBodyInnerHTML(R"HTML(
<style>.scroller {width: 400px; height: 400px; overflow: auto;
@@ -169,7 +172,9 @@ TEST_F(CompositingReasonFinderTest, OnlyScrollingStickyPositionPromoted) {
->GetCompositingState());
}
-TEST_F(CompositingReasonFinderTest, CompositingReasonsForAnimation) {
+void CompositingReasonFinderTest::CheckCompositingReasonsForAnimation(
+ bool supports_transform_animation) {
+ auto* object = GetLayoutObjectByElementId("target");
scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
style->SetSubtreeWillChangeContents(false);
@@ -177,32 +182,47 @@ TEST_F(CompositingReasonFinderTest, CompositingReasonsForAnimation) {
style->SetHasCurrentOpacityAnimation(false);
style->SetHasCurrentFilterAnimation(false);
style->SetHasCurrentBackdropFilterAnimation(false);
+ object->SetStyle(style);
+
EXPECT_EQ(CompositingReason::kNone,
- CompositingReasonFinder::CompositingReasonsForAnimation(*style));
+ CompositingReasonFinder::CompositingReasonsForAnimation(*object));
+
+ CompositingReasons expected_compositing_reason_for_transform_animation =
+ supports_transform_animation
+ ? CompositingReason::kActiveTransformAnimation
+ : CompositingReason::kNone;
style->SetHasCurrentTransformAnimation(true);
- EXPECT_EQ(CompositingReason::kActiveTransformAnimation,
- CompositingReasonFinder::CompositingReasonsForAnimation(*style));
+ EXPECT_EQ(expected_compositing_reason_for_transform_animation,
+ CompositingReasonFinder::CompositingReasonsForAnimation(*object));
style->SetHasCurrentOpacityAnimation(true);
- EXPECT_EQ(CompositingReason::kActiveTransformAnimation |
+ EXPECT_EQ(expected_compositing_reason_for_transform_animation |
CompositingReason::kActiveOpacityAnimation,
- CompositingReasonFinder::CompositingReasonsForAnimation(*style));
+ CompositingReasonFinder::CompositingReasonsForAnimation(*object));
style->SetHasCurrentFilterAnimation(true);
- EXPECT_EQ(CompositingReason::kActiveTransformAnimation |
+ EXPECT_EQ(expected_compositing_reason_for_transform_animation |
CompositingReason::kActiveOpacityAnimation |
CompositingReason::kActiveFilterAnimation,
- CompositingReasonFinder::CompositingReasonsForAnimation(*style));
+ CompositingReasonFinder::CompositingReasonsForAnimation(*object));
style->SetHasCurrentBackdropFilterAnimation(true);
- EXPECT_EQ(CompositingReason::kActiveTransformAnimation |
+ EXPECT_EQ(expected_compositing_reason_for_transform_animation |
CompositingReason::kActiveOpacityAnimation |
CompositingReason::kActiveFilterAnimation |
CompositingReason::kActiveBackdropFilterAnimation,
- CompositingReasonFinder::CompositingReasonsForAnimation(*style));
- EXPECT_EQ(CompositingReason::kComboActiveAnimation,
- CompositingReasonFinder::CompositingReasonsForAnimation(*style));
+ CompositingReasonFinder::CompositingReasonsForAnimation(*object));
+}
+
+TEST_F(CompositingReasonFinderTest, CompositingReasonsForAnimationBox) {
+ SetBodyInnerHTML("<div id='target'>Target</div>");
+ CheckCompositingReasonsForAnimation(/*supports_transform_animation*/ true);
+}
+
+TEST_F(CompositingReasonFinderTest, CompositingReasonsForAnimationInline) {
+ SetBodyInnerHTML("<span id='target'>Target</span>");
+ CheckCompositingReasonsForAnimation(/*supports_transform_animation*/ false);
}
TEST_F(CompositingReasonFinderTest, DontPromoteEmptyIframe) {
@@ -241,7 +261,7 @@ TEST_F(CompositingReasonFinderTest, PromoteCrossOriginIframe) {
ASSERT_TRUE(iframe_layer);
ASSERT_FALSE(To<HTMLFrameOwnerElement>(iframe)
->ContentFrame()
- ->IsCrossOriginSubframe());
+ ->IsCrossOriginToMainFrame());
EXPECT_EQ(kNotComposited, iframe_layer->DirectCompositingReasons());
SetBodyInnerHTML(R"HTML(
@@ -256,8 +276,8 @@ TEST_F(CompositingReasonFinderTest, PromoteCrossOriginIframe) {
ASSERT_TRUE(iframe_layer);
ASSERT_TRUE(To<HTMLFrameOwnerElement>(iframe)
->ContentFrame()
- ->IsCrossOriginSubframe());
- EXPECT_EQ(CompositingReason::kCrossOriginIframe,
+ ->IsCrossOriginToMainFrame());
+ EXPECT_EQ(CompositingReason::kIFrame,
iframe_layer->DirectCompositingReasons());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index 966c367af23..0b9f70b8b36 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h"
#include "base/macros.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
@@ -209,8 +210,6 @@ CompositingRequirementsUpdater::CompositingRequirementsUpdater(
LayoutView& layout_view)
: layout_view_(layout_view) {}
-CompositingRequirementsUpdater::~CompositingRequirementsUpdater() = default;
-
void CompositingRequirementsUpdater::Update(
PaintLayer* root,
CompositingReasonsStats& compositing_reasons_stats) {
@@ -597,7 +596,10 @@ void CompositingRequirementsUpdater::UpdateRecursive(
CompositingReason::kClipsCompositingDescendants);
if ((!child_recursion_data.testing_overlap_ &&
!is_composited_clipping_layer) ||
- layer->GetLayoutObject().StyleRef().HasCurrentTransformAnimation())
+ layer->GetLayoutObject().StyleRef().HasCurrentTransformAnimation() ||
+ ((direct_reasons & CompositingReason::kScrollDependentPosition) &&
+ base::FeatureList::IsEnabled(
+ features::kAssumeOverlapAfterFixedOrStickyPosition)))
current_recursion_data.testing_overlap_ = false;
if (child_recursion_data.compositing_ancestor_ == layer)
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
index dcb9464a6d9..6f1d051d9da 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h
@@ -42,7 +42,6 @@ class CompositingRequirementsUpdater {
public:
CompositingRequirementsUpdater(LayoutView&);
- ~CompositingRequirementsUpdater();
// Recurse through the layers in z-index and overflow order (which is
// equivalent to painting order)
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
index 8100621f58d..15bb8e48d76 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater_test.cc
@@ -4,13 +4,12 @@
#include "third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.h"
-#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
namespace blink {
@@ -128,19 +127,7 @@ TEST_F(CompositingRequirementsUpdaterTest,
EXPECT_EQ(IntRect(0, 0, 100, 100), tracking->Invalidations()[0].rect);
}
-class CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D
- : public CompositingRequirementsUpdaterTest {
- public:
- CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D() {
- scoped_feature_list_.InitAndEnableFeature(
- blink::features::kDoNotCompositeTrivial3D);
- }
-
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D,
- NonTrivial3DTransforms) {
+TEST_F(CompositingRequirementsUpdaterTest, NonTrivial3DTransforms) {
ScopedCSSIndependentTransformPropertiesForTest feature_scope(true);
SetBodyInnerHTML(R"HTML(
@@ -169,7 +156,7 @@ TEST_F(CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D,
ToLayoutBox(transform_3d)->Layer()->GetCompositingReasons());
const auto* transform_2d = GetLayoutObjectByElementId("2d-transform");
EXPECT_FALSE(transform_2d->StyleRef().HasNonTrivial3DTransformOperation());
- EXPECT_FALSE(ToLayoutBox(transform_2d)->Layer()->GetCompositingReasons());
+ EXPECT_TRUE(ToLayoutBox(transform_2d)->Layer()->GetCompositingReasons());
const auto* transform_3d_translate_z =
GetLayoutObjectByElementId("3d-transform-translate-z");
@@ -182,7 +169,7 @@ TEST_F(CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D,
GetLayoutObjectByElementId("2d-transform-translate-z");
EXPECT_FALSE(
transform_2d_translate_z->StyleRef().HasNonTrivial3DTransformOperation());
- EXPECT_FALSE(
+ EXPECT_TRUE(
ToLayoutBox(transform_2d_translate_z)->Layer()->GetCompositingReasons());
const auto* transform_2d_translate_x =
GetLayoutObjectByElementId("2d-transform-translate-x");
@@ -197,7 +184,7 @@ TEST_F(CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D,
ToLayoutBox(xform_rot_x_3d)->Layer()->GetCompositingReasons());
const auto* xform_rot_x_2d = GetLayoutObjectByElementId("2d-transform-rot-x");
EXPECT_FALSE(xform_rot_x_2d->StyleRef().HasNonTrivial3DTransformOperation());
- EXPECT_FALSE(ToLayoutBox(xform_rot_x_2d)->Layer()->GetCompositingReasons());
+ EXPECT_TRUE(ToLayoutBox(xform_rot_x_2d)->Layer()->GetCompositingReasons());
const auto* xform_rot_z_2d = GetLayoutObjectByElementId("2d-transform-rot-z");
EXPECT_FALSE(xform_rot_z_2d->StyleRef().HasNonTrivial3DTransformOperation());
EXPECT_FALSE(ToLayoutBox(xform_rot_z_2d)->Layer()->GetCompositingReasons());
@@ -208,7 +195,7 @@ TEST_F(CompositingRequirementsUpdaterTestWithDoNotCompositeTrivial3D,
ToLayoutBox(rotation_y_3d)->Layer()->GetCompositingReasons());
const auto* rotation_y_2d = GetLayoutObjectByElementId("2d-rotation-y");
EXPECT_FALSE(rotation_y_2d->StyleRef().HasNonTrivial3DTransformOperation());
- EXPECT_FALSE(ToLayoutBox(rotation_y_2d)->Layer()->GetCompositingReasons());
+ EXPECT_TRUE(ToLayoutBox(rotation_y_2d)->Layer()->GetCompositingReasons());
const auto* rotation_z_2d = GetLayoutObjectByElementId("2d-rotation-z");
EXPECT_FALSE(rotation_z_2d->StyleRef().HasNonTrivial3DTransformOperation());
EXPECT_FALSE(ToLayoutBox(rotation_z_2d)->Layer()->GetCompositingReasons());
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 55dfee22796..cefe3499d81 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "cc/layers/picture_layer.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/scroll_and_scale_set.h"
+#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -48,9 +52,9 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
// Both sets the inner html and runs the document lifecycle.
void InitializeWithHTML(LocalFrame& frame, const String& html_content) {
- frame.GetDocument()->body()->SetInnerHTMLFromString(html_content);
+ frame.GetDocument()->body()->setInnerHTML(html_content);
frame.GetDocument()->View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ DocumentUpdateReason::kTest);
}
WebLocalFrame* LocalMainFrame() { return web_view_helper_->LocalMainFrame(); }
@@ -66,7 +70,8 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
}
const cc::Layer* CcLayerByDOMElementId(const char* id) {
- return CcLayersByDOMElementId(RootCcLayer(), id)[0];
+ auto layers = CcLayersByDOMElementId(RootCcLayer(), id);
+ return layers.IsEmpty() ? nullptr : layers[0];
}
cc::LayerTreeHost* LayerTreeHost() {
@@ -80,7 +85,7 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
void UpdateAllLifecyclePhases() {
WebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
+ DocumentUpdateReason::kTest);
}
private:
@@ -92,7 +97,7 @@ class CompositingTest : public PaintTestConfigurations, public testing::Test {
std::unique_ptr<frame_test_helpers::WebViewHelper> web_view_helper_;
};
-INSTANTIATE_LAYER_LIST_TEST_SUITE_P(CompositingTest);
+INSTANTIATE_PAINT_TEST_SUITE_P(CompositingTest);
TEST_P(CompositingTest, DidScrollCallbackAfterScrollableAreaChanges) {
InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(),
@@ -121,9 +126,13 @@ TEST_P(CompositingTest, DidScrollCallbackAfterScrollableAreaChanges) {
CompositorElementId scroll_element_id = scrollable_area->GetScrollElementId();
const auto* overflow_scroll_layer =
CcLayerByCcElementId(RootCcLayer(), scroll_element_id);
- EXPECT_TRUE(overflow_scroll_layer->scrollable());
- EXPECT_EQ(overflow_scroll_layer->scroll_container_bounds(),
- gfx::Size(100, 100));
+ const auto* scroll_node =
+ RootCcLayer()
+ ->layer_tree_host()
+ ->property_trees()
+ ->scroll_tree.FindNodeFromElementId(scroll_element_id);
+ EXPECT_TRUE(scroll_node->scrollable);
+ EXPECT_EQ(scroll_node->container_bounds, gfx::Size(100, 100));
// Ensure a synthetic impl-side scroll offset propagates to the scrollable
// area using the DidScroll callback.
@@ -151,8 +160,10 @@ TEST_P(CompositingTest, DidScrollCallbackAfterScrollableAreaChanges) {
// apply impl-side offsets without crashing.
ASSERT_EQ(overflow_scroll_layer,
CcLayerByCcElementId(RootCcLayer(), scroll_element_id));
- const_cast<cc::Layer*>(overflow_scroll_layer)
- ->SetScrollOffsetFromImplSide(gfx::ScrollOffset(0, 3));
+ scroll_and_scale_set.scrolls[0] = {scroll_element_id, gfx::ScrollOffset(0, 1),
+ base::nullopt};
+ overflow_scroll_layer->layer_tree_host()->ApplyScrollAndScale(
+ &scroll_and_scale_set);
UpdateAllLifecyclePhases();
EXPECT_FALSE(CcLayerByCcElementId(RootCcLayer(), scroll_element_id));
@@ -173,9 +184,13 @@ TEST_P(CompositingTest, FrameViewScroll) {
auto* scrollable_area = GetLocalFrameView()->LayoutViewport();
EXPECT_NE(nullptr, scrollable_area);
- const auto* scroll_layer = CcLayerByCcElementId(
- RootCcLayer(), scrollable_area->GetScrollElementId());
- EXPECT_TRUE(scroll_layer->scrollable());
+ const auto* scroll_node = RootCcLayer()
+ ->layer_tree_host()
+ ->property_trees()
+ ->scroll_tree.FindNodeFromElementId(
+ scrollable_area->GetScrollElementId());
+ ASSERT_TRUE(scroll_node);
+ EXPECT_TRUE(scroll_node->scrollable);
// Ensure a synthetic impl-side scroll offset propagates to the scrollable
// area using the DidScroll callback.
@@ -184,16 +199,31 @@ TEST_P(CompositingTest, FrameViewScroll) {
scroll_and_scale_set.scrolls.push_back({scrollable_area->GetScrollElementId(),
gfx::ScrollOffset(0, 1),
base::nullopt});
- scroll_layer->layer_tree_host()->ApplyScrollAndScale(&scroll_and_scale_set);
+ RootCcLayer()->layer_tree_host()->ApplyScrollAndScale(&scroll_and_scale_set);
UpdateAllLifecyclePhases();
EXPECT_EQ(ScrollOffset(0, 1), scrollable_area->GetScrollOffset());
}
+TEST_P(CompositingTest, WillChangeTransformHint) {
+ InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+ <style>
+ #willChange {
+ width: 100px;
+ height: 100px;
+ will-change: transform;
+ background: blue;
+ }
+ </style>
+ <div id="willChange"></div>
+ )HTML");
+ UpdateAllLifecyclePhases();
+ auto* layer = CcLayerByDOMElementId("willChange");
+ EXPECT_TRUE(layer->has_will_change_transform_hint());
+}
+
class CompositingSimTest : public PaintTestConfigurations, public SimTest {
public:
void InitializeWithHTML(const String& html) {
- WebView().MainFrameWidget()->Resize(WebSize(800, 600));
-
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
request.Complete(html);
@@ -206,7 +236,8 @@ class CompositingSimTest : public PaintTestConfigurations, public SimTest {
}
const cc::Layer* CcLayerByDOMElementId(const char* id) {
- return CcLayersByDOMElementId(RootCcLayer(), id)[0];
+ auto layers = CcLayersByDOMElementId(RootCcLayer(), id);
+ return layers.IsEmpty() ? nullptr : layers[0];
}
Element* GetElementById(const AtomicString& id) {
@@ -215,17 +246,16 @@ class CompositingSimTest : public PaintTestConfigurations, public SimTest {
void UpdateAllLifecyclePhases() {
WebView().MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
+ DocumentUpdateReason::kTest);
}
void UpdateAllLifecyclePhasesExceptPaint() {
- WebView().MainFrameWidget()->UpdateLifecycle(
- WebWidget::LifecycleUpdate::kPrePaint,
- WebWidget::LifecycleUpdateReason::kTest);
+ WebView().MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kPrePaint,
+ DocumentUpdateReason::kTest);
}
cc::PropertyTrees* GetPropertyTrees() {
- return Compositor().layer_tree_host().property_trees();
+ return Compositor().layer_tree_host()->property_trees();
}
cc::TransformNode* GetTransformNode(const cc::Layer* layer) {
@@ -240,17 +270,18 @@ class CompositingSimTest : public PaintTestConfigurations, public SimTest {
PaintArtifactCompositor* paint_artifact_compositor() {
return MainFrame().GetFrameView()->GetPaintArtifactCompositor();
}
+
+ private:
+ void SetUp() override {
+ SimTest::SetUp();
+ // Ensure a non-empty size so painting does not early-out.
+ WebView().Resize(WebSize(800, 600));
+ }
};
-INSTANTIATE_LAYER_LIST_TEST_SUITE_P(CompositingSimTest);
+INSTANTIATE_PAINT_TEST_SUITE_P(CompositingSimTest);
TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -259,6 +290,7 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
width: 100px;
height: 100px;
will-change: transform;
+ background: lightblue;
}
</style>
<div id='a'></div>
@@ -267,19 +299,12 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
Compositor().BeginFrame();
- auto* a_element = GetElementById("a");
auto* a_layer = CcLayerByDOMElementId("a");
- DCHECK_EQ(a_layer->element_id(), CompositorElementIdFromUniqueObjectId(
- a_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
auto* b_element = GetElementById("b");
auto* b_layer = CcLayerByDOMElementId("b");
- DCHECK_EQ(b_layer->element_id(), CompositorElementIdFromUniqueObjectId(
- b_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
// Initially, neither a nor b should have a layer that should push properties.
- cc::LayerTreeHost& host = Compositor().layer_tree_host();
+ cc::LayerTreeHost& host = *Compositor().layer_tree_host();
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(a_layer));
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(b_layer));
@@ -296,12 +321,6 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateEarlierLayers) {
}
TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateLaterLayers) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -310,6 +329,7 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateLaterLayers) {
width: 100px;
height: 100px;
will-change: transform;
+ background: lightblue;
}
</style>
<div id='a'></div>
@@ -321,22 +341,12 @@ TEST_P(CompositingSimTest, LayerUpdatesDoNotInvalidateLaterLayers) {
auto* a_element = GetElementById("a");
auto* a_layer = CcLayerByDOMElementId("a");
- DCHECK_EQ(a_layer->element_id(), CompositorElementIdFromUniqueObjectId(
- a_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
auto* b_element = GetElementById("b");
auto* b_layer = CcLayerByDOMElementId("b");
- DCHECK_EQ(b_layer->element_id(), CompositorElementIdFromUniqueObjectId(
- b_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
- auto* c_element = GetElementById("c");
auto* c_layer = CcLayerByDOMElementId("c");
- DCHECK_EQ(c_layer->element_id(), CompositorElementIdFromUniqueObjectId(
- c_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
// Initially, no layer should need to push properties.
- cc::LayerTreeHost& host = Compositor().layer_tree_host();
+ cc::LayerTreeHost& host = *Compositor().layer_tree_host();
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(a_layer));
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(b_layer));
EXPECT_FALSE(host.LayersThatShouldPushProperties().count(c_layer));
@@ -374,7 +384,7 @@ TEST_P(CompositingSimTest,
Compositor().BeginFrame();
// Initially the host should not need to sync.
- cc::LayerTreeHost& layer_tree_host = Compositor().layer_tree_host();
+ cc::LayerTreeHost& layer_tree_host = *Compositor().layer_tree_host();
EXPECT_FALSE(layer_tree_host.needs_full_tree_sync());
int sequence_number = GetPropertyTrees()->sequence_number;
EXPECT_GT(sequence_number, 0);
@@ -394,12 +404,6 @@ TEST_P(CompositingSimTest,
// non-layer-list mode, this occurs in BuildPropertyTreesInternal (see:
// SetLayerPropertyChangedForChild).
TEST_P(CompositingSimTest, LayerSubtreeTransformPropertyChanged) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -409,6 +413,7 @@ TEST_P(CompositingSimTest, LayerSubtreeTransformPropertyChanged) {
height: 100px;
will-change: transform;
transform: translate(10px, 10px);
+ background: lightgreen;
}
#inner {
width: 100px;
@@ -426,16 +431,7 @@ TEST_P(CompositingSimTest, LayerSubtreeTransformPropertyChanged) {
auto* outer_element = GetElementById("outer");
auto* outer_element_layer = CcLayerByDOMElementId("outer");
- DCHECK_EQ(outer_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- outer_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
- auto* inner_element = GetElementById("inner");
auto* inner_element_layer = CcLayerByDOMElementId("inner");
- DCHECK_EQ(inner_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- inner_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
// Initially, no layer should have |subtree_property_changed| set.
EXPECT_FALSE(outer_element_layer->subtree_property_changed());
@@ -471,12 +467,6 @@ TEST_P(CompositingSimTest, LayerSubtreeTransformPropertyChanged) {
// |transform_changed| set. In non-layer-list mode, this occurs in
// cc::TransformTree::OnTransformAnimated and cc::Layer::SetTransform.
TEST_P(CompositingSimTest, DirectTransformPropertyUpdate) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -486,6 +476,7 @@ TEST_P(CompositingSimTest, DirectTransformPropertyUpdate) {
height: 100px;
will-change: transform;
transform: translate(10px, 10px) scale(1, 2);
+ background: lightgreen;
}
#inner {
width: 100px;
@@ -503,10 +494,6 @@ TEST_P(CompositingSimTest, DirectTransformPropertyUpdate) {
auto* outer_element = GetElementById("outer");
auto* outer_element_layer = CcLayerByDOMElementId("outer");
- DCHECK_EQ(outer_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- outer_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
auto transform_tree_index = outer_element_layer->transform_tree_index();
auto* transform_node =
GetPropertyTrees()->transform_tree.Node(transform_tree_index);
@@ -531,12 +518,6 @@ TEST_P(CompositingSimTest, DirectTransformPropertyUpdate) {
// the changed value of a directly updated transform is still set if some other
// change causes PaintArtifactCompositor to run and do non-direct updates.
TEST_P(CompositingSimTest, DirectTransformPropertyUpdateCausesChange) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -546,6 +527,7 @@ TEST_P(CompositingSimTest, DirectTransformPropertyUpdateCausesChange) {
height: 100px;
will-change: transform;
transform: translate(1px, 2px);
+ background: lightgreen;
}
#inner {
width: 100px;
@@ -564,20 +546,12 @@ TEST_P(CompositingSimTest, DirectTransformPropertyUpdateCausesChange) {
auto* outer_element = GetElementById("outer");
auto* outer_element_layer = CcLayerByDOMElementId("outer");
- DCHECK_EQ(outer_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- outer_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
auto outer_transform_tree_index = outer_element_layer->transform_tree_index();
auto* outer_transform_node =
GetPropertyTrees()->transform_tree.Node(outer_transform_tree_index);
auto* inner_element = GetElementById("inner");
auto* inner_element_layer = CcLayerByDOMElementId("inner");
- DCHECK_EQ(inner_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- inner_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
auto inner_transform_tree_index = inner_element_layer->transform_tree_index();
auto* inner_transform_node =
GetPropertyTrees()->transform_tree.Node(inner_transform_tree_index);
@@ -680,12 +654,6 @@ TEST_P(CompositingSimTest, AffectedByOuterViewportBoundsDelta) {
// |transform_changed| set. In non-layer-list mode, this occurs in
// cc::Layer::SetTransformOrigin.
TEST_P(CompositingSimTest, DirectTransformOriginPropertyUpdate) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -695,6 +663,7 @@ TEST_P(CompositingSimTest, DirectTransformOriginPropertyUpdate) {
height: 100px;
transform: rotate3d(3, 2, 1, 45deg);
transform-origin: 10px 10px 100px;
+ background: lightblue;
}
</style>
<div id='box'></div>
@@ -704,10 +673,6 @@ TEST_P(CompositingSimTest, DirectTransformOriginPropertyUpdate) {
auto* box_element = GetElementById("box");
auto* box_element_layer = CcLayerByDOMElementId("box");
- DCHECK_EQ(box_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- box_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
auto transform_tree_index = box_element_layer->transform_tree_index();
auto* transform_node =
GetPropertyTrees()->transform_tree.Node(transform_tree_index);
@@ -803,12 +768,6 @@ TEST_P(CompositingSimTest, LayerSubtreeEffectPropertyChanged) {
// This test is similar to |LayerSubtreeTransformPropertyChanged| but for
// clip property node changes.
TEST_P(CompositingSimTest, LayerSubtreeClipPropertyChanged) {
- // TODO(crbug.com/765003): CAP may make different layerization decisions and
- // we cannot guarantee that both divs will be composited in this test. When
- // CAP gets closer to launch, this test should be updated to pass.
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- return;
-
InitializeWithHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -819,6 +778,7 @@ TEST_P(CompositingSimTest, LayerSubtreeClipPropertyChanged) {
will-change: transform;
position: absolute;
clip: rect(10px, 80px, 70px, 40px);
+ background: lightgreen;
}
#inner {
width: 100px;
@@ -836,12 +796,7 @@ TEST_P(CompositingSimTest, LayerSubtreeClipPropertyChanged) {
auto* outer_element = GetElementById("outer");
auto* outer_element_layer = CcLayerByDOMElementId("outer");
- auto* inner_element = GetElementById("inner");
auto* inner_element_layer = CcLayerByDOMElementId("inner");
- DCHECK_EQ(inner_element_layer->element_id(),
- CompositorElementIdFromUniqueObjectId(
- inner_element->GetLayoutObject()->UniqueId(),
- CompositorElementIdNamespace::kPrimary));
// Initially, no layer should have |subtree_property_changed| set.
EXPECT_FALSE(outer_element_layer->subtree_property_changed());
@@ -1118,4 +1073,143 @@ TEST_P(CompositingSimTest, NoRenderSurfaceWithAxisAlignedTransformAnimation) {
}
}
+TEST_P(CompositingSimTest, PromoteCrossOriginIframe) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ blink::features::kCompositeCrossOriginIframes, true);
+ InitializeWithHTML("<!DOCTYPE html><iframe id=iframe sandbox></iframe>");
+ Compositor().BeginFrame();
+ EXPECT_TRUE(CcLayerByDOMElementId("iframe"));
+}
+
+// On initial layout, the iframe is not yet loaded and is not considered
+// cross origin. This test ensures the iframe is promoted due to being cross
+// origin after the iframe loads.
+TEST_P(CompositingSimTest, PromoteCrossOriginIframeAfterLoading) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ blink::features::kCompositeCrossOriginIframes, true);
+
+ SimRequest main_resource("https://origin-a.com/a.html", "text/html");
+ SimRequest frame_resource("https://origin-b.com/b.html", "text/html");
+
+ LoadURL("https://origin-a.com/a.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="iframe" src="https://origin-b.com/b.html"></iframe>
+ )HTML");
+ frame_resource.Complete("<!DOCTYPE html>");
+ Compositor().BeginFrame();
+
+ EXPECT_TRUE(CcLayerByDOMElementId("iframe"));
+}
+
+// An iframe that is cross-origin to the parent should be composited. This test
+// sets up nested frames with domains A -> B -> A. Both the child and grandchild
+// frames should be composited because they are cross-origin to their parent.
+TEST_P(CompositingSimTest, PromoteCrossOriginToParent) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ blink::features::kCompositeCrossOriginIframes, true);
+
+ SimRequest main_resource("https://origin-a.com/a.html", "text/html");
+ SimRequest child_resource("https://origin-b.com/b.html", "text/html");
+ SimRequest grandchild_resource("https://origin-a.com/c.html", "text/html");
+
+ LoadURL("https://origin-a.com/a.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="main_iframe" src="https://origin-b.com/b.html"></iframe>
+ )HTML");
+ child_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="child_iframe" src="https://origin-a.com/c.html"></iframe>
+ )HTML");
+ grandchild_resource.Complete("<!DOCTYPE html>");
+ Compositor().BeginFrame();
+
+ EXPECT_TRUE(CcLayerByDOMElementId("main_iframe"));
+ EXPECT_TRUE(CcLayerByDOMElementId("child_iframe"));
+}
+
+// Initially the iframe is cross-origin and should be composited. After changing
+// to same-origin, the frame should no longer be composited.
+TEST_P(CompositingSimTest, PromoteCrossOriginIframeAfterDomainChange) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ blink::features::kCompositeCrossOriginIframes, true);
+
+ SimRequest main_resource("https://origin-a.com/a.html", "text/html");
+ SimRequest frame_resource("https://sub.origin-a.com/b.html", "text/html");
+
+ LoadURL("https://origin-a.com/a.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="iframe" src="https://sub.origin-a.com/b.html"></iframe>
+ )HTML");
+ frame_resource.Complete("<!DOCTYPE html>");
+ Compositor().BeginFrame();
+
+ EXPECT_TRUE(CcLayerByDOMElementId("iframe"));
+
+ auto* iframe_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("iframe"));
+ NonThrowableExceptionState exception_state;
+ GetDocument().setDomain(String("origin-a.com"), exception_state);
+ iframe_element->contentDocument()->setDomain(String("origin-a.com"),
+ exception_state);
+ // We may not have scheduled a visual update so force an update instead of
+ // using BeginFrame.
+ UpdateAllLifecyclePhases();
+
+ EXPECT_FALSE(CcLayerByDOMElementId("iframe"));
+}
+
+// This test sets up nested frames with domains A -> B -> A. Initially, the
+// child frame and grandchild frame should be composited. After changing the
+// child frame to A (same-origin), both child and grandchild frames should no
+// longer be composited.
+TEST_P(CompositingSimTest, PromoteCrossOriginToParentIframeAfterDomainChange) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatureState(
+ blink::features::kCompositeCrossOriginIframes, true);
+
+ SimRequest main_resource("https://origin-a.com/a.html", "text/html");
+ SimRequest child_resource("https://sub.origin-a.com/b.html", "text/html");
+ SimRequest grandchild_resource("https://origin-a.com/c.html", "text/html");
+
+ LoadURL("https://origin-a.com/a.html");
+ main_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="main_iframe" src="https://sub.origin-a.com/b.html"></iframe>
+ )HTML");
+ child_resource.Complete(R"HTML(
+ <!DOCTYPE html>
+ <iframe id="child_iframe" src="https://origin-a.com/c.html"></iframe>
+ )HTML");
+ grandchild_resource.Complete("<!DOCTYPE html>");
+ Compositor().BeginFrame();
+
+ EXPECT_TRUE(CcLayerByDOMElementId("main_iframe"));
+ EXPECT_TRUE(CcLayerByDOMElementId("child_iframe"));
+
+ auto* main_iframe_element =
+ To<HTMLIFrameElement>(GetDocument().getElementById("main_iframe"));
+ NonThrowableExceptionState exception_state;
+ GetDocument().setDomain(String("origin-a.com"), exception_state);
+ auto* child_iframe_element = To<HTMLIFrameElement>(
+ main_iframe_element->contentDocument()->getElementById("child_iframe"));
+ child_iframe_element->contentDocument()->setDomain(String("origin-a.com"),
+ exception_state);
+ main_iframe_element->contentDocument()->setDomain(String("origin-a.com"),
+ exception_state);
+
+ // We may not have scheduled a visual update so force an update instead of
+ // using BeginFrame.
+ UpdateAllLifecyclePhases();
+
+ EXPECT_FALSE(CcLayerByDOMElementId("main_iframe"));
+ EXPECT_FALSE(CcLayerByDOMElementId("child_iframe"));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc
index 8be2ec4a1b5..fce32e76d78 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_as_text.cc
@@ -15,9 +15,7 @@ namespace {
std::unique_ptr<JSONObject> GraphicsLayerAsJSON(const GraphicsLayer* layer,
LayerTreeFlags flags) {
- // Intentionally passing through 0, 0 for the offset from the transform node
- // as this dump implementation doesn't support transform/position information.
- auto json = CCLayerAsJSON(layer->CcLayer(), flags, FloatPoint());
+ auto json = CCLayerAsJSON(layer->CcLayer(), flags);
// Content dumped after this point, down to AppendAdditionalInfoAsJSON, is
// specific to GraphicsLayer tree dumping when called from one of the methods
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
index bceebbc05cd..6e5eaa164fe 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
@@ -38,8 +38,6 @@ namespace blink {
GraphicsLayerTreeBuilder::GraphicsLayerTreeBuilder() = default;
-GraphicsLayerTreeBuilder::~GraphicsLayerTreeBuilder() = default;
-
static bool ShouldAppendLayer(const PaintLayer& layer) {
auto* video_element =
DynamicTo<HTMLVideoElement>(layer.GetLayoutObject().GetNode());
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
index 88e607b9442..b1ef0a4f661 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.h
@@ -39,7 +39,6 @@ class GraphicsLayerTreeBuilder {
public:
GraphicsLayerTreeBuilder();
- ~GraphicsLayerTreeBuilder();
void Rebuild(PaintLayer&, GraphicsLayerVector&);
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
index e1df9970626..3026c276c50 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.cc
@@ -104,8 +104,6 @@ GraphicsLayerUpdater::UpdateContext::CompositingStackingContext() const {
GraphicsLayerUpdater::GraphicsLayerUpdater() : needs_rebuild_tree_(false) {}
-GraphicsLayerUpdater::~GraphicsLayerUpdater() = default;
-
void GraphicsLayerUpdater::Update(
PaintLayer& layer,
Vector<PaintLayer*>& layers_needing_paint_invalidation) {
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h
index 9a98a937df3..54c765cc6db 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/graphics_layer_updater.h
@@ -39,7 +39,6 @@ class GraphicsLayerUpdater {
public:
GraphicsLayerUpdater();
- ~GraphicsLayerUpdater();
enum UpdateType {
kDoNotForceUpdate,
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index 6fcd60085aa..3f7a2b6c166 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -66,10 +66,9 @@
namespace blink {
PaintLayerCompositor::PaintLayerCompositor(LayoutView& layout_view)
- : layout_view_(layout_view),
- has_accelerated_compositing_(layout_view.GetDocument()
- .GetSettings()
- ->GetAcceleratedCompositingEnabled()) {}
+ : layout_view_(layout_view) {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+}
PaintLayerCompositor::~PaintLayerCompositor() {
DCHECK_EQ(root_layer_attachment_, kRootLayerUnattached);
@@ -135,7 +134,9 @@ void PaintLayerCompositor::EnableCompositingModeIfNeeded() {
bool PaintLayerCompositor::RootShouldAlwaysComposite() const {
// If compositing is disabled for the WebView, then nothing composites.
- if (!has_accelerated_compositing_)
+ if (!layout_view_.GetDocument()
+ .GetSettings()
+ ->GetAcceleratedCompositingEnabled())
return false;
// Local roots composite always, when compositing is enabled globally.
if (layout_view_.GetFrame()->IsLocalRoot())
@@ -150,23 +151,11 @@ bool PaintLayerCompositor::RootShouldAlwaysComposite() const {
}
void PaintLayerCompositor::UpdateAcceleratedCompositingSettings() {
- // AcceleratedCompositing setting does not change after initialization.
- DCHECK_EQ(has_accelerated_compositing_,
- layout_view_.GetDocument()
- .GetSettings()
- ->GetAcceleratedCompositingEnabled());
-
root_should_always_composite_dirty_ = true;
if (root_layer_attachment_ != kRootLayerUnattached)
RootLayer()->SetNeedsCompositingInputsUpdate();
}
-bool PaintLayerCompositor::PreferCompositingToLCDTextEnabled() const {
- return layout_view_.GetDocument()
- .GetSettings()
- ->GetPreferCompositingToLCDTextEnabled();
-}
-
static LayoutVideo* FindFullscreenVideoLayoutObject(Document& document) {
// Recursively find the document that is in fullscreen.
Element* fullscreen_element = Fullscreen::FullscreenElementFrom(document);
@@ -181,9 +170,7 @@ static LayoutVideo* FindFullscreenVideoLayoutObject(Document& document) {
if (!IsA<HTMLVideoElement>(fullscreen_element))
return nullptr;
LayoutObject* layout_object = fullscreen_element->GetLayoutObject();
- if (!layout_object)
- return nullptr;
- return ToLayoutVideo(layout_object);
+ return To<LayoutVideo>(layout_object);
}
void PaintLayerCompositor::UpdateIfNeededRecursive(
@@ -321,7 +308,9 @@ GraphicsLayer* PaintLayerCompositor::OverlayFullscreenVideoGraphicsLayer()
void PaintLayerCompositor::UpdateWithoutAcceleratedCompositing(
CompositingUpdateType update_type) {
- DCHECK(!HasAcceleratedCompositing());
+ DCHECK(!layout_view_.GetDocument()
+ .GetSettings()
+ ->GetAcceleratedCompositingEnabled());
if (update_type >= kCompositingUpdateAfterCompositingInputChange) {
CompositingInputsUpdater(RootLayer(), GetCompositingInputsRoot()).Update();
@@ -379,7 +368,9 @@ void PaintLayerCompositor::UpdateIfNeeded(
CompositingUpdateType update_type = pending_update_type_;
pending_update_type_ = kCompositingUpdateNone;
- if (!HasAcceleratedCompositing()) {
+ if (!layout_view_.GetDocument()
+ .GetSettings()
+ ->GetAcceleratedCompositingEnabled()) {
UpdateWithoutAcceleratedCompositing(update_type);
Lifecycle().AdvanceTo(
std::min(DocumentLifecycle::kCompositingClean, target_state));
@@ -563,14 +554,6 @@ bool PaintLayerCompositor::AllocateOrClearCompositedLayerMapping(
layer->ClearClipRects(kPaintingClipRects);
- // If a fixed position layer gained/lost a compositedLayerMapping or the
- // reason not compositing it changed, the scrolling coordinator needs to
- // recalculate whether it can do fast scrolling.
- if (ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator()) {
- scrolling_coordinator->FrameViewFixedObjectsDidChange(
- layout_view_.GetFrameView());
- }
-
// Compositing state affects whether to create paint offset translation of
// this layer, and amount of paint offset translation of descendants.
layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
@@ -658,13 +641,13 @@ GraphicsLayer* PaintLayerCompositor::RootGraphicsLayer() const {
return nullptr;
}
-GraphicsLayer* PaintLayerCompositor::GetXrImmersiveDomOverlayLayer() const {
+GraphicsLayer* PaintLayerCompositor::GetXrOverlayLayer() const {
// immersive-ar DOM overlay mode is very similar to fullscreen video, using
// the AR camera image instead of a video element as a background that's
// separately composited in the browser. The fullscreened DOM content is shown
// on top of that, same as HTML video controls.
DCHECK(IsMainFrame());
- if (!layout_view_.GetDocument().IsImmersiveArOverlay())
+ if (!layout_view_.GetDocument().IsXrOverlay())
return nullptr;
Element* fullscreen_element =
@@ -695,7 +678,7 @@ GraphicsLayer* PaintLayerCompositor::PaintRootGraphicsLayer() const {
// Start from the full screen overlay layer if exists. Other layers will be
// skipped during painting.
- if (auto* layer = GetXrImmersiveDomOverlayLayer())
+ if (auto* layer = GetXrOverlayLayer())
return layer;
if (auto* layer = OverlayFullscreenVideoGraphicsLayer())
return layer;
@@ -719,8 +702,10 @@ bool PaintLayerCompositor::CanBeComposited(const PaintLayer* layer) const {
const bool has_compositor_animation =
CompositingReasonFinder::CompositingReasonsForAnimation(
- *layer->GetLayoutObject().Style()) != CompositingReason::kNone;
- return has_accelerated_compositing_ &&
+ layer->GetLayoutObject()) != CompositingReason::kNone;
+ return layout_view_.GetDocument()
+ .GetSettings()
+ ->GetAcceleratedCompositingEnabled() &&
(has_compositor_animation || !layer->SubtreeIsInvisible()) &&
layer->IsSelfPaintingLayer() &&
!layer->GetLayoutObject().IsLayoutFlowThread() &&
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index b54493ba61e..e747e628c87 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -95,13 +95,6 @@ class CORE_EXPORT PaintLayerCompositor {
// to the native view/window system.
void SetCompositingModeEnabled(bool);
- // Returns true if the accelerated compositing is enabled
- bool HasAcceleratedCompositing() const {
- return has_accelerated_compositing_;
- }
-
- bool PreferCompositingToLCDTextEnabled() const;
-
bool RootShouldAlwaysComposite() const;
// Notifies about changes to PreferCompositingToLCDText or
@@ -195,10 +188,9 @@ class CORE_EXPORT PaintLayerCompositor {
bool IsMainFrame() const;
- GraphicsLayer* GetXrImmersiveDomOverlayLayer() const;
+ GraphicsLayer* GetXrOverlayLayer() const;
LayoutView& layout_view_;
- const bool has_accelerated_compositing_ = true;
bool compositing_ = false;
diff --git a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc
index f79b67a6769..669148c9936 100644
--- a/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor_test.cc
@@ -36,7 +36,8 @@ TEST_F(PaintLayerCompositorTest, AdvancingToCompositingInputsClean) {
box_layer->SetNeedsCompositingInputsUpdate();
- GetDocument().View()->UpdateLifecycleToCompositingInputsClean();
+ GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
+ DocumentUpdateReason::kTest);
EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
GetDocument().Lifecycle().GetState());
EXPECT_FALSE(box_layer->NeedsCompositingInputsUpdate());
@@ -63,7 +64,8 @@ TEST_F(PaintLayerCompositorTest,
// Update the lifecycle to CompositingInputsClean. This should not start the
// animation lifecycle.
- GetDocument().View()->UpdateLifecycleToCompositingInputsClean();
+ GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
+ DocumentUpdateReason::kTest);
EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
GetDocument().Lifecycle().GetState());
@@ -110,7 +112,8 @@ TEST_F(PaintLayerCompositorTest, CompositingInputsUpdateStopsContainStrict) {
EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate());
EXPECT_TRUE(target->NeedsCompositingInputsUpdate());
- GetDocument().View()->UpdateLifecycleToCompositingInputsClean();
+ GetDocument().View()->UpdateLifecycleToCompositingInputsClean(
+ DocumentUpdateReason::kTest);
EXPECT_EQ(DocumentLifecycle::kCompositingInputsClean,
GetDocument().Lifecycle().GetState());
EXPECT_FALSE(wrapper->NeedsCompositingInputsUpdate());
diff --git a/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc b/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc
index 25432d2d1ea..269bc6bc6df 100644
--- a/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/css_mask_painter.cc
@@ -23,8 +23,9 @@ base::Optional<IntRect> CSSMaskPainter::MaskBoundingBox(
SVGResourcesCache::CachedResourcesForLayoutObject(object);
LayoutSVGResourceMasker* masker = resources ? resources->Masker() : nullptr;
if (masker) {
- return EnclosingIntRect(
- masker->ResourceBoundingBox(object.ObjectBoundingBox()));
+ const FloatRect reference_box =
+ SVGResources::ReferenceBoxForEffects(object);
+ return EnclosingIntRect(masker->ResourceBoundingBox(reference_box));
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc b/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
index 2e1600aba58..75934b0f5c3 100644
--- a/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
+++ b/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.cc
@@ -41,13 +41,26 @@ CustomScrollbarTheme* CustomScrollbarTheme::GetCustomScrollbarTheme() {
return &theme;
}
+ScrollbarPart CustomScrollbarTheme::HitTest(const Scrollbar& scrollbar,
+ const IntPoint& test_position) {
+ auto result = ScrollbarTheme::HitTest(scrollbar, test_position);
+ if (result == kScrollbarBGPart) {
+ // The ScrollbarTheme knows nothing about the double buttons.
+ if (ButtonRect(scrollbar, kBackButtonEndPart).Contains(test_position))
+ return kBackButtonEndPart;
+ if (ButtonRect(scrollbar, kForwardButtonStartPart).Contains(test_position))
+ return kForwardButtonStartPart;
+ }
+ return result;
+}
+
void CustomScrollbarTheme::ButtonSizesAlongTrackAxis(const Scrollbar& scrollbar,
int& before_size,
int& after_size) {
- IntRect first_button = BackButtonRect(scrollbar, kBackButtonStartPart);
- IntRect second_button = ForwardButtonRect(scrollbar, kForwardButtonStartPart);
- IntRect third_button = BackButtonRect(scrollbar, kBackButtonEndPart);
- IntRect fourth_button = ForwardButtonRect(scrollbar, kForwardButtonEndPart);
+ IntRect first_button = ButtonRect(scrollbar, kBackButtonStartPart);
+ IntRect second_button = ButtonRect(scrollbar, kForwardButtonStartPart);
+ IntRect third_button = ButtonRect(scrollbar, kBackButtonEndPart);
+ IntRect fourth_button = ButtonRect(scrollbar, kForwardButtonEndPart);
if (scrollbar.Orientation() == kHorizontalScrollbar) {
before_size = first_button.Width() + second_button.Width();
after_size = third_button.Width() + fourth_button.Width();
@@ -74,14 +87,17 @@ int CustomScrollbarTheme::MinimumThumbLength(const Scrollbar& scrollbar) {
return To<CustomScrollbar>(scrollbar).MinimumThumbLength();
}
-IntRect CustomScrollbarTheme::BackButtonRect(const Scrollbar& scrollbar,
- ScrollbarPart part_type) {
+IntRect CustomScrollbarTheme::ButtonRect(const Scrollbar& scrollbar,
+ ScrollbarPart part_type) {
return To<CustomScrollbar>(scrollbar).ButtonRect(part_type);
}
-IntRect CustomScrollbarTheme::ForwardButtonRect(const Scrollbar& scrollbar,
- ScrollbarPart part_type) {
- return To<CustomScrollbar>(scrollbar).ButtonRect(part_type);
+IntRect CustomScrollbarTheme::BackButtonRect(const Scrollbar& scrollbar) {
+ return ButtonRect(scrollbar, kBackButtonStartPart);
+}
+
+IntRect CustomScrollbarTheme::ForwardButtonRect(const Scrollbar& scrollbar) {
+ return ButtonRect(scrollbar, kForwardButtonEndPart);
}
IntRect CustomScrollbarTheme::TrackRect(const Scrollbar& scrollbar) {
@@ -141,17 +157,15 @@ void CustomScrollbarTheme::PaintTrackAndButtons(GraphicsContext& context,
PaintPart(context, scrollbar, scrollbar.FrameRect(), kScrollbarBGPart);
if (HasButtons(scrollbar)) {
- PaintButton(context, scrollbar,
- BackButtonRect(scrollbar, kBackButtonStartPart),
+ PaintButton(context, scrollbar, ButtonRect(scrollbar, kBackButtonStartPart),
kBackButtonStartPart);
- PaintButton(context, scrollbar,
- BackButtonRect(scrollbar, kBackButtonEndPart),
+ PaintButton(context, scrollbar, ButtonRect(scrollbar, kBackButtonEndPart),
kBackButtonEndPart);
PaintButton(context, scrollbar,
- ForwardButtonRect(scrollbar, kForwardButtonStartPart),
+ ButtonRect(scrollbar, kForwardButtonStartPart),
kForwardButtonStartPart);
PaintButton(context, scrollbar,
- ForwardButtonRect(scrollbar, kForwardButtonEndPart),
+ ButtonRect(scrollbar, kForwardButtonEndPart),
kForwardButtonEndPart);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h b/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h
index 7b72703ac91..eecbdda3cd1 100644
--- a/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h
+++ b/chromium/third_party/blink/renderer/core/paint/custom_scrollbar_theme.h
@@ -44,8 +44,8 @@ class CustomScrollbarTheme final : public ScrollbarTheme {
return GetTheme().ScrollbarThickness(control_size);
}
- WebScrollbarButtonsPlacement ButtonsPlacement() const override {
- return GetTheme().ButtonsPlacement();
+ bool NativeThemeHasButtons() override {
+ return GetTheme().NativeThemeHasButtons();
}
void PaintScrollCorner(GraphicsContext&,
@@ -89,11 +89,13 @@ class CustomScrollbarTheme final : public ScrollbarTheme {
const CustomScrollbar* = nullptr);
protected:
+ ScrollbarPart HitTest(const Scrollbar&, const IntPoint&) override;
+
bool HasButtons(const Scrollbar&) override;
bool HasThumb(const Scrollbar&) override;
- IntRect BackButtonRect(const Scrollbar&, ScrollbarPart) override;
- IntRect ForwardButtonRect(const Scrollbar&, ScrollbarPart) override;
+ IntRect BackButtonRect(const Scrollbar&) override;
+ IntRect ForwardButtonRect(const Scrollbar&) override;
IntRect TrackRect(const Scrollbar&) override;
void PaintTrackAndButtons(GraphicsContext&,
@@ -112,6 +114,7 @@ class CustomScrollbarTheme final : public ScrollbarTheme {
const IntRect&) override;
private:
+ IntRect ButtonRect(const Scrollbar&, ScrollbarPart);
void PaintScrollbarBackground(GraphicsContext&, const Scrollbar&);
void PaintTrackBackground(GraphicsContext&, const Scrollbar&, const IntRect&);
void PaintTrackPiece(GraphicsContext&,
diff --git a/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc b/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc
index 41bd8afeb85..0d0459e9d09 100644
--- a/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/document_marker_painter.cc
@@ -95,25 +95,8 @@ sk_sp<PaintRecord> RecordMarker(Color blink_color) {
void DrawDocumentMarker(GraphicsContext& context,
const FloatPoint& pt,
float width,
- DocumentMarker::MarkerType marker_type,
- float zoom) {
- DCHECK(marker_type == DocumentMarker::kSpelling ||
- marker_type == DocumentMarker::kGrammar);
-
- DEFINE_STATIC_LOCAL(
- PaintRecord*, spelling_marker,
- (RecordMarker(
- LayoutTheme::GetTheme().PlatformSpellingMarkerUnderlineColor())
- .release()));
- DEFINE_STATIC_LOCAL(
- PaintRecord*, grammar_marker,
- (RecordMarker(
- LayoutTheme::GetTheme().PlatformGrammarMarkerUnderlineColor())
- .release()));
- auto* const marker = marker_type == DocumentMarker::kSpelling
- ? spelling_marker
- : grammar_marker;
-
+ float zoom,
+ PaintRecord* const marker) {
// Position already includes zoom and device scale factor.
SkScalar origin_x = WebCoreFloatToSkScalar(pt.X());
SkScalar origin_y = WebCoreFloatToSkScalar(pt.Y());
@@ -185,14 +168,49 @@ void DocumentMarkerPainter::PaintStyleableMarkerUnderline(
marker.UseTextColor()
? style.VisitedDependentColor(GetCSSPropertyWebkitTextFillColor())
: marker.UnderlineColor();
- context.SetStrokeColor(marker_color);
-
- context.SetStrokeThickness(line_thickness);
- context.DrawLineForText(
- FloatPoint(
- box_origin.left + start,
- (box_origin.top + logical_height.ToInt() - line_thickness).ToFloat()),
- width);
+ if (marker.UnderlineStyle() !=
+ ui::mojom::ImeTextSpanUnderlineStyle::kSquiggle) {
+ context.SetStrokeColor(marker_color);
+ context.SetStrokeThickness(line_thickness);
+ // Set the style of the underline if there is any.
+ switch (marker.UnderlineStyle()) {
+ case ui::mojom::ImeTextSpanUnderlineStyle::kDash:
+ context.SetStrokeStyle(StrokeStyle::kDashedStroke);
+ break;
+ case ui::mojom::ImeTextSpanUnderlineStyle::kDot:
+ context.SetStrokeStyle(StrokeStyle::kDottedStroke);
+ break;
+ case ui::mojom::ImeTextSpanUnderlineStyle::kSolid:
+ context.SetStrokeStyle(StrokeStyle::kSolidStroke);
+ break;
+ case ui::mojom::ImeTextSpanUnderlineStyle::kNone:
+ context.SetStrokeStyle(StrokeStyle::kNoStroke);
+ break;
+ case ui::mojom::ImeTextSpanUnderlineStyle::kSquiggle:
+ // Wavy stroke style is not implemented in DrawLineForText so we handle
+ // it specially in the else condition below only for composition
+ // markers.
+ break;
+ }
+ context.DrawLineForText(
+ FloatPoint(box_origin.left + start,
+ (box_origin.top + logical_height.ToInt() - line_thickness)
+ .ToFloat()),
+ width);
+ } else {
+ // For wavy underline format we use this logic that is very similar to
+ // spelling/grammar squiggles format. Only applicable for composition
+ // markers for now.
+ if (marker.GetType() == DocumentMarker::kComposition) {
+ sk_sp<PaintRecord> composition_marker = (RecordMarker(marker_color));
+ DrawDocumentMarker(
+ context,
+ FloatPoint((box_origin.left + start).ToFloat(),
+ (box_origin.top + logical_height.ToInt() - line_thickness)
+ .ToFloat()),
+ width, line_thickness, composition_marker.get());
+ }
+ }
}
void DocumentMarkerPainter::PaintDocumentMarker(
@@ -210,7 +228,7 @@ void DocumentMarkerPainter::PaintDocumentMarker(
// place the underline at the bottom of the text, but in larger fonts that's
// not so good so we pin to two pixels under the baseline.
float zoom = style.EffectiveZoom();
- int line_thickness = kMarkerHeight * zoom;
+ int line_thickness = static_cast<int>(ceilf(kMarkerHeight * zoom));
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
DCHECK(font_data);
@@ -227,10 +245,24 @@ void DocumentMarkerPainter::PaintDocumentMarker(
// prevent a big gap.
underline_offset = baseline + 2 * zoom;
}
+ DEFINE_STATIC_LOCAL(
+ PaintRecord*, spelling_marker,
+ (RecordMarker(
+ LayoutTheme::GetTheme().PlatformSpellingMarkerUnderlineColor())
+ .release()));
+ DEFINE_STATIC_LOCAL(
+ PaintRecord*, grammar_marker,
+ (RecordMarker(
+ LayoutTheme::GetTheme().PlatformGrammarMarkerUnderlineColor())
+ .release()));
+
+ auto* const marker = marker_type == DocumentMarker::kSpelling
+ ? spelling_marker
+ : grammar_marker;
DrawDocumentMarker(context,
FloatPoint((box_origin.left + local_rect.X()).ToFloat(),
(box_origin.top + underline_offset).ToFloat()),
- local_rect.Width().ToFloat(), marker_type, zoom);
+ local_rect.Width().ToFloat(), zoom, marker);
}
TextPaintStyle DocumentMarkerPainter::ComputeTextPaintStyleFrom(
diff --git a/chromium/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
index df0263b1c2c..d4b65ec7134 100644
--- a/chromium/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ellipsis_box_painter.cc
@@ -22,7 +22,7 @@ void EllipsisBoxPainter::Paint(const PaintInfo& paint_info,
const LayoutPoint& paint_offset,
LayoutUnit line_top,
LayoutUnit line_bottom) {
- if (paint_info.phase == PaintPhase::kSelection)
+ if (paint_info.phase == PaintPhase::kSelectionDragImage)
return;
const ComputedStyle& style = ellipsis_box_.GetLineLayoutItem().StyleRef(
diff --git a/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc
index 43663833e74..9b93bd124de 100644
--- a/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/embedded_object_painter.cc
@@ -31,7 +31,6 @@ static Font ReplacementTextFont() {
font_description.SetWeight(BoldWeightValue());
font_description.SetComputedSize(font_description.SpecifiedSize());
Font font(font_description);
- font.Update(nullptr);
return font;
}
@@ -43,7 +42,7 @@ void EmbeddedObjectPainter::PaintReplaced(const PaintInfo& paint_info,
return;
}
- if (paint_info.phase == PaintPhase::kSelection)
+ if (paint_info.phase == PaintPhase::kSelectionDragImage)
return;
GraphicsContext& context = paint_info.context;
diff --git a/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc b/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc
index f6fa95b1c13..900b20688cf 100644
--- a/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/filter_effect_builder.cc
@@ -27,7 +27,6 @@
#include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
#include <algorithm>
-#include "third_party/blink/public/platform/web_point.h"
#include "third_party/blink/renderer/core/style/filter_operations.h"
#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
#include "third_party/blink/renderer/core/svg/svg_filter_element.h"
@@ -165,14 +164,16 @@ FilterEffect* FilterEffectBuilder::BuildFilterEffect(
Vector<float> input_parameters = GrayscaleMatrix(
To<BasicColorMatrixFilterOperation>(filter_operation)->Amount());
effect = MakeGarbageCollected<FEColorMatrix>(
- parent_filter, FECOLORMATRIX_TYPE_MATRIX, input_parameters);
+ parent_filter, FECOLORMATRIX_TYPE_MATRIX,
+ std::move(input_parameters));
break;
}
case FilterOperation::SEPIA: {
Vector<float> input_parameters = SepiaMatrix(
To<BasicColorMatrixFilterOperation>(filter_operation)->Amount());
effect = MakeGarbageCollected<FEColorMatrix>(
- parent_filter, FECOLORMATRIX_TYPE_MATRIX, input_parameters);
+ parent_filter, FECOLORMATRIX_TYPE_MATRIX,
+ std::move(input_parameters));
break;
}
case FilterOperation::SATURATE: {
@@ -180,7 +181,8 @@ FilterEffect* FilterEffectBuilder::BuildFilterEffect(
input_parameters.push_back(clampTo<float>(
To<BasicColorMatrixFilterOperation>(filter_operation)->Amount()));
effect = MakeGarbageCollected<FEColorMatrix>(
- parent_filter, FECOLORMATRIX_TYPE_SATURATE, input_parameters);
+ parent_filter, FECOLORMATRIX_TYPE_SATURATE,
+ std::move(input_parameters));
break;
}
case FilterOperation::HUE_ROTATE: {
@@ -188,7 +190,8 @@ FilterEffect* FilterEffectBuilder::BuildFilterEffect(
input_parameters.push_back(clampTo<float>(
To<BasicColorMatrixFilterOperation>(filter_operation)->Amount()));
effect = MakeGarbageCollected<FEColorMatrix>(
- parent_filter, FECOLORMATRIX_TYPE_HUEROTATE, input_parameters);
+ parent_filter, FECOLORMATRIX_TYPE_HUEROTATE,
+ std::move(input_parameters));
break;
}
case FilterOperation::INVERT: {
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
index 3eaac6137e5..97c06979db0 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -151,16 +151,15 @@ void FirstMeaningfulPaintDetector::RegisterNotifySwapTime(PaintEvent event) {
WrapCrossThreadWeakPersistent(this), event));
}
-void FirstMeaningfulPaintDetector::ReportSwapTime(
- PaintEvent event,
- WebWidgetClient::SwapResult result,
- base::TimeTicks timestamp) {
+void FirstMeaningfulPaintDetector::ReportSwapTime(PaintEvent event,
+ WebSwapResult result,
+ base::TimeTicks timestamp) {
DCHECK(event == PaintEvent::kProvisionalFirstMeaningfulPaint);
DCHECK_GT(outstanding_swap_promise_count_, 0U);
--outstanding_swap_promise_count_;
// If the swap fails for any reason, we use the timestamp when the SwapPromise
- // was broken. |result| == WebWidgetClient::SwapResult::kDidNotSwapSwapFails
+ // was broken. |result| == WebSwapResult::kDidNotSwapSwapFails
// usually means the compositor decided not swap because there was no actual
// damage, which can happen when what's being painted isn't visible. In this
// case, the timestamp will be consistent with the case where the swap
@@ -224,7 +223,7 @@ void FirstMeaningfulPaintDetector::SetTickClockForTesting(
g_clock = clock;
}
-void FirstMeaningfulPaintDetector::Trace(blink::Visitor* visitor) {
+void FirstMeaningfulPaintDetector::Trace(Visitor* visitor) {
visitor->Trace(paint_timing_);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index a0c9db2c3f2..a093acfcf0b 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_FIRST_MEANINGFUL_PAINT_DETECTOR_H_
#include "base/macros.h"
-#include "third_party/blink/public/web/web_widget_client.h"
+#include "third_party/blink/public/web/web_swap_result.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/paint/paint_event.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -39,14 +39,14 @@ class CORE_EXPORT FirstMeaningfulPaintDetector
int visible_height);
void NotifyInputEvent();
void NotifyPaint();
- void ReportSwapTime(PaintEvent, WebWidgetClient::SwapResult, base::TimeTicks);
+ void ReportSwapTime(PaintEvent, WebSwapResult, base::TimeTicks);
void NotifyFirstContentfulPaint(base::TimeTicks swap_stamp);
void OnNetwork2Quiet();
// The caller owns the |clock| which must outlive the paint detector.
static void SetTickClockForTesting(const base::TickClock* clock);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
enum HadUserInput { kNoUserInput, kHadUserInput, kHadUserInputEnumMax };
diff --git a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
index b4b2344a792..b448877213e 100644
--- a/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
@@ -49,7 +49,7 @@ class FirstMeaningfulPaintDetectorTest : public PageTestBase {
for (int i = 0; i < new_elements; i++)
builder.Append("<span>a</span>");
GetDocument().write(builder.ToString());
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
Detector().NotifyPaint();
}
@@ -62,15 +62,14 @@ class FirstMeaningfulPaintDetectorTest : public PageTestBase {
void ClearFirstPaintSwapPromise() {
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
- GetPaintTiming().ReportSwapTime(
- PaintEvent::kFirstPaint, WebWidgetClient::SwapResult::kDidSwap, Now());
+ GetPaintTiming().ReportSwapTime(PaintEvent::kFirstPaint,
+ WebSwapResult::kDidSwap, Now());
}
void ClearFirstContentfulPaintSwapPromise() {
platform()->AdvanceClock(base::TimeDelta::FromMilliseconds(1));
GetPaintTiming().ReportSwapTime(PaintEvent::kFirstContentfulPaint,
- WebWidgetClient::SwapResult::kDidSwap,
- Now());
+ WebSwapResult::kDidSwap, Now());
}
void ClearProvisionalFirstMeaningfulPaintSwapPromise() {
@@ -81,7 +80,7 @@ class FirstMeaningfulPaintDetectorTest : public PageTestBase {
void ClearProvisionalFirstMeaningfulPaintSwapPromise(
base::TimeTicks timestamp) {
Detector().ReportSwapTime(PaintEvent::kProvisionalFirstMeaningfulPaint,
- WebWidgetClient::SwapResult::kDidSwap, timestamp);
+ WebSwapResult::kDidSwap, timestamp);
}
unsigned OutstandingDetectorSwapPromiseCount() {
diff --git a/chromium/third_party/blink/renderer/core/paint/fragment_data.h b/chromium/third_party/blink/renderer/core/paint/fragment_data.h
index c0b43ea28f1..9ae6c02600d 100644
--- a/chromium/third_party/blink/renderer/core/paint/fragment_data.h
+++ b/chromium/third_party/blink/renderer/core/paint/fragment_data.h
@@ -100,15 +100,16 @@ class CORE_EXPORT FragmentData {
EnsureRareData().logical_top_in_flow_thread = top;
}
- // The pagination offset is the additional factor to add in to map
- // from flow thread coordinates relative to the enclosing pagination
- // layer, to visual coordiantes relative to that pagination layer.
- PhysicalOffset PaginationOffset() const {
- return rare_data_ ? rare_data_->pagination_offset : PhysicalOffset();
+ // The pagination offset is the additional factor to add in to map from flow
+ // thread coordinates relative to the enclosing pagination layer, to visual
+ // coordinates relative to that pagination layer. Not to be used in LayoutNG
+ // fragment painting.
+ PhysicalOffset LegacyPaginationOffset() const {
+ return rare_data_ ? rare_data_->legacy_pagination_offset : PhysicalOffset();
}
- void SetPaginationOffset(const PhysicalOffset& pagination_offset) {
+ void SetLegacyPaginationOffset(const PhysicalOffset& pagination_offset) {
if (rare_data_ || pagination_offset != PhysicalOffset())
- EnsureRareData().pagination_offset = pagination_offset;
+ EnsureRareData().legacy_pagination_offset = pagination_offset;
}
bool IsClipPathCacheValid() const {
@@ -256,7 +257,7 @@ class CORE_EXPORT FragmentData {
IntRect partial_invalidation_visual_rect;
// Fragment specific data.
- PhysicalOffset pagination_offset;
+ PhysicalOffset legacy_pagination_offset;
LayoutUnit logical_top_in_flow_thread;
std::unique_ptr<ObjectPaintProperties> paint_properties;
std::unique_ptr<RefCountedPropertyTreeState> local_border_box_properties;
diff --git a/chromium/third_party/blink/renderer/core/paint/frame_paint_timing.h b/chromium/third_party/blink/renderer/core/paint/frame_paint_timing.h
index 0416f1138b9..1d6d98f6f76 100644
--- a/chromium/third_party/blink/renderer/core/paint/frame_paint_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/frame_paint_timing.h
@@ -33,7 +33,7 @@ class FramePaintTiming {
private:
GraphicsContext& context_;
- Member<const LocalFrame> frame_;
+ const LocalFrame* frame_;
DISALLOW_COPY_AND_ASSIGN(FramePaintTiming);
};
diff --git a/chromium/third_party/blink/renderer/core/paint/frame_painter.h b/chromium/third_party/blink/renderer/core/paint/frame_painter.h
index 05c33f8fba5..ee2368328ee 100644
--- a/chromium/third_party/blink/renderer/core/paint/frame_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/frame_painter.h
@@ -28,7 +28,7 @@ class FramePainter {
private:
const LocalFrameView& GetFrameView();
- Member<const LocalFrameView> frame_view_;
+ const LocalFrameView* frame_view_;
static bool in_paint_contents_;
DISALLOW_COPY_AND_ASSIGN(FramePainter);
diff --git a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
index dc2531bcd1b..c3b20fb9d6d 100644
--- a/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
@@ -71,7 +71,7 @@ TEST_P(HTMLCanvasPainterTestForCAP, Canvas2DLayerAppearsInLayerTree) {
// Insert a <canvas> and force it into accelerated mode.
// Not using SetBodyInnerHTML() because we need to test before document
// lifecyle update.
- GetDocument().body()->SetInnerHTMLFromString("<canvas width=300 height=200>");
+ GetDocument().body()->setInnerHTML("<canvas width=300 height=200>");
auto* element = To<HTMLCanvasElement>(GetDocument().body()->firstChild());
CanvasContextCreationAttributesCore attributes;
attributes.alpha = true;
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc b/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
index 47b371c6cfa..4a824465ff5 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing.cc
@@ -101,7 +101,7 @@ void ImageElementTiming::NotifyImagePainted(
it->value.is_painted_ = true;
NotifyImagePaintedInternal(layout_object->GetNode(), *layout_object,
*cached_image, current_paint_chunk_properties,
- it->value.load_time_);
+ it->value.load_time_, nullptr);
}
}
@@ -110,7 +110,8 @@ void ImageElementTiming::NotifyImagePaintedInternal(
const LayoutObject& layout_object,
const ImageResourceContent& cached_image,
const PropertyTreeState& current_paint_chunk_properties,
- base::TimeTicks load_time) {
+ base::TimeTicks load_time,
+ const IntRect* image_border) {
LocalFrame* frame = GetSupplementable()->GetFrame();
DCHECK(frame == layout_object.GetDocument().GetFrame());
DCHECK(node);
@@ -134,8 +135,13 @@ void ImageElementTiming::NotifyImagePaintedInternal(
if (!layout_object.HasNonZeroEffectiveOpacity())
return;
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(&layout_object);
+
FloatRect intersection_rect = ElementTimingUtils::ComputeIntersectionRect(
- frame, layout_object.FirstFragment().VisualRect(),
+ frame,
+ image_border ? *image_border
+ : layout_object.FragmentsVisualRectBoundingBox(),
current_paint_chunk_properties);
const AtomicString attr =
element->FastGetAttribute(html_names::kElementtimingAttr);
@@ -147,25 +153,35 @@ void ImageElementTiming::NotifyImagePaintedInternal(
DCHECK(layout_object.GetDocument().GetSecurityOrigin());
// It's ok to expose rendering timestamp for data URIs so exclude those from
// the Timing-Allow-Origin check.
- bool response_tainting_not_basic = false;
- bool tainted_origin_flag = false;
- if (!url.ProtocolIsData() &&
- !Performance::PassesTimingAllowCheck(
+ if (!url.ProtocolIsData()) {
+ bool timing_allow_check = false;
+ // Use the TimingAllowPassed() check from the response if OutOfBlinkCors is
+ // enabled. If it is not enabled then that flag is not computed, so use to
+ // the single PassesTimingAllowCheck(), which is incorrect because it does
+ // not check the full redirect chain. See crbug.com/1003943.
+ if (RuntimeEnabledFeatures::OutOfBlinkCorsEnabled()) {
+ timing_allow_check = cached_image.GetResponse().TimingAllowPassed();
+ } else {
+ bool response_tainting_not_basic = false;
+ bool tainted_origin_flag = false;
+ timing_allow_check = Performance::PassesTimingAllowCheck(
cached_image.GetResponse(), cached_image.GetResponse(),
*layout_object.GetDocument().GetSecurityOrigin(),
- &layout_object.GetDocument(), &response_tainting_not_basic,
- &tainted_origin_flag)) {
- WindowPerformance* performance =
- DOMWindowPerformance::performance(*GetSupplementable());
- if (performance) {
- // Create an entry with a |startTime| of 0.
- performance->AddElementTiming(
- ImagePaintString(), url.GetString(), intersection_rect,
- base::TimeTicks(), load_time, attr,
- cached_image.IntrinsicSize(kDoNotRespectImageOrientation), id,
- element);
+ layout_object.GetDocument().ToExecutionContext(),
+ &response_tainting_not_basic, &tainted_origin_flag);
+ }
+ if (!timing_allow_check) {
+ WindowPerformance* performance =
+ DOMWindowPerformance::performance(*GetSupplementable());
+ if (performance) {
+ // Create an entry with a |startTime| of 0.
+ performance->AddElementTiming(
+ ImagePaintString(), url.GetString(), intersection_rect,
+ base::TimeTicks(), load_time, attr,
+ cached_image.IntrinsicSize(respect_orientation), id, element);
+ }
+ return;
}
- return;
}
// If the image URL is a data URL ("data:image/..."), then the |name| of the
@@ -177,7 +193,7 @@ void ImageElementTiming::NotifyImagePaintedInternal(
: url.GetString();
element_timings_.emplace_back(MakeGarbageCollected<ElementTimingInfo>(
image_url, intersection_rect, load_time, attr,
- cached_image.IntrinsicSize(kDoNotRespectImageOrientation), id, element));
+ cached_image.IntrinsicSize(respect_orientation), id, element));
// Only queue a swap promise when |element_timings_| was empty. All of the
// records in |element_timings_| will be processed when the promise succeeds
// or fails, and at that time the vector is cleared.
@@ -192,7 +208,8 @@ void ImageElementTiming::NotifyImagePaintedInternal(
void ImageElementTiming::NotifyBackgroundImagePainted(
Node* node,
const StyleFetchedImage* background_image,
- const PropertyTreeState& current_paint_chunk_properties) {
+ const PropertyTreeState& current_paint_chunk_properties,
+ const IntRect& image_border) {
DCHECK(node);
DCHECK(background_image);
@@ -218,11 +235,11 @@ void ImageElementTiming::NotifyBackgroundImagePainted(
info.is_painted_ = true;
NotifyImagePaintedInternal(layout_object->GetNode(), *layout_object,
*cached_image, current_paint_chunk_properties,
- it->value);
+ it->value, &image_border);
}
}
-void ImageElementTiming::ReportImagePaintSwapTime(WebWidgetClient::SwapResult,
+void ImageElementTiming::ReportImagePaintSwapTime(WebSwapResult,
base::TimeTicks timestamp) {
WindowPerformance* performance =
DOMWindowPerformance::performance(*GetSupplementable());
@@ -243,7 +260,7 @@ void ImageElementTiming::NotifyImageRemoved(const LayoutObject* layout_object,
images_notified_.erase(std::make_pair(layout_object, image));
}
-void ImageElementTiming::Trace(blink::Visitor* visitor) {
+void ImageElementTiming::Trace(Visitor* visitor) {
visitor->Trace(element_timings_);
visitor->Trace(background_image_timestamps_);
Supplement<LocalDOMWindow>::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing.h b/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
index 1f6ac8fbcd0..18db86a4047 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing.h
@@ -7,7 +7,7 @@
#include <utility>
-#include "third_party/blink/public/web/web_widget_client.h"
+#include "third_party/blink/public/web/web_swap_result.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -57,12 +57,13 @@ class CORE_EXPORT ImageElementTiming final
void NotifyBackgroundImagePainted(
Node*,
const StyleFetchedImage* background_image,
- const PropertyTreeState& current_paint_chunk_properties);
+ const PropertyTreeState& current_paint_chunk_properties,
+ const IntRect& image_border);
void NotifyImageRemoved(const LayoutObject*,
const ImageResourceContent* image);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
friend class ImageElementTimingTest;
@@ -72,11 +73,11 @@ class CORE_EXPORT ImageElementTiming final
const LayoutObject&,
const ImageResourceContent& cached_image,
const PropertyTreeState& current_paint_chunk_properties,
- base::TimeTicks load_time);
+ base::TimeTicks load_time,
+ const IntRect* image_border);
// Callback for the swap promise. Reports paint timestamps.
- void ReportImagePaintSwapTime(WebWidgetClient::SwapResult,
- base::TimeTicks timestamp);
+ void ReportImagePaintSwapTime(WebSwapResult, base::TimeTicks timestamp);
// Class containing information about image element timing.
class ElementTimingInfo final : public GarbageCollected<ElementTimingInfo> {
@@ -97,7 +98,7 @@ class CORE_EXPORT ImageElementTiming final
element(element) {}
~ElementTimingInfo() = default;
- void Trace(blink::Visitor* visitor) { visitor->Trace(element); }
+ void Trace(Visitor* visitor) { visitor->Trace(element); }
String url;
FloatRect rect;
diff --git a/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc b/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
index 1349b35b968..c39619a98a3 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_element_timing_test.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -22,7 +23,8 @@ extern bool IsExplicitlyRegisteredForTiming(const LayoutObject* layout_object);
}
-class ImageElementTimingTest : public testing::Test {
+class ImageElementTimingTest : public testing::Test,
+ public PaintTestConfigurations {
protected:
void SetUp() override {
web_view_helper_.Initialize();
@@ -87,8 +89,7 @@ class ImageElementTimingTest : public testing::Test {
->MainFrameImpl()
->GetFrame()
->View()
- ->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ ->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
}
frame_test_helpers::WebViewHelper web_view_helper_;
@@ -108,13 +109,18 @@ class ImageElementTimingTest : public testing::Test {
}
};
-TEST_F(ImageElementTimingTest, TestIsExplicitlyRegisteredForTiming) {
+INSTANTIATE_PAINT_TEST_SUITE_P(ImageElementTimingTest);
+
+TEST_P(ImageElementTimingTest, TestIsExplicitlyRegisteredForTiming) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), R"HTML(
<img id="missing-attribute" style='width: 100px; height: 100px;'/>
- <img id="unset-attribute" elementtiming style='width: 100px; height: 100px;'/>
- <img id="empty-attribute" elementtiming="" style='width: 100px; height: 100px;'/>
- <img id="valid-attribute" elementtiming="valid-id" style='width: 100px; height: 100px;'/>
+ <img id="unset-attribute" elementtiming
+ style='width: 100px; height: 100px;'/>
+ <img id="empty-attribute" elementtiming=""
+ style='width: 100px; height: 100px;'/>
+ <img id="valid-attribute" elementtiming="valid-id"
+ style='width: 100px; height: 100px;'/>
)HTML",
base_url_);
@@ -142,7 +148,7 @@ TEST_F(ImageElementTimingTest, TestIsExplicitlyRegisteredForTiming) {
"should be explicitly registered.";
}
-TEST_F(ImageElementTimingTest, IgnoresUnmarkedElement) {
+TEST_P(ImageElementTimingTest, IgnoresUnmarkedElement) {
// Tests that, if the 'elementtiming' attribute is missing, the element isn't
// considered by ImageElementTiming.
frame_test_helpers::LoadHTMLString(
@@ -157,12 +163,13 @@ TEST_F(ImageElementTimingTest, IgnoresUnmarkedElement) {
std::make_pair(layout_image, layout_image->CachedImage())));
}
-TEST_F(ImageElementTimingTest, ImageInsideSVG) {
+TEST_P(ImageElementTimingTest, ImageInsideSVG) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), R"HTML(
<svg>
<foreignObject width="100" height="100">
- <img elementtiming="image-inside-svg" id="target" style='width: 100px; height: 100px;'/>
+ <img elementtiming="image-inside-svg" id="target"
+ style='width: 100px; height: 100px;'/>
</foreignObject>
</svg>
)HTML",
@@ -176,13 +183,14 @@ TEST_F(ImageElementTimingTest, ImageInsideSVG) {
std::make_pair(layout_image, layout_image->CachedImage())));
}
-TEST_F(ImageElementTimingTest, ImageInsideNonRenderedSVG) {
+TEST_P(ImageElementTimingTest, ImageInsideNonRenderedSVG) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), R"HTML(
<svg mask="url(#mask)">
<mask id="mask">
<foreignObject width="100" height="100">
- <img elementtiming="image-inside-svg" id="target" style='width: 100px; height: 100px;'/>
+ <img elementtiming="image-inside-svg" id="target"
+ style='width: 100px; height: 100px;'/>
</foreignObject>
</mask>
<rect width="100" height="100" fill="green"/>
@@ -196,10 +204,11 @@ TEST_F(ImageElementTimingTest, ImageInsideNonRenderedSVG) {
EXPECT_FALSE(GetLayoutObjectById("target"));
}
-TEST_F(ImageElementTimingTest, ImageRemoved) {
+TEST_P(ImageElementTimingTest, ImageRemoved) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), R"HTML(
- <img elementtiming="will-be-removed" id="target" style='width: 100px; height: 100px;'/>
+ <img elementtiming="will-be-removed" id="target"
+ style='width: 100px; height: 100px;'/>
)HTML",
base_url_);
LayoutImage* layout_image = SetImageResource("target", 5, 5);
@@ -214,11 +223,12 @@ TEST_F(ImageElementTimingTest, ImageRemoved) {
EXPECT_EQ(ImagesNotifiedSize(), 0u);
}
-TEST_F(ImageElementTimingTest, SVGImageRemoved) {
+TEST_P(ImageElementTimingTest, SVGImageRemoved) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), R"HTML(
<svg>
- <image elementtiming="svg-will-be-removed" id="target" style='width: 100px; height: 100px;'/>
+ <image elementtiming="svg-will-be-removed" id="target"
+ style='width: 100px; height: 100px;'/>
</svg>
)HTML",
base_url_);
@@ -234,7 +244,7 @@ TEST_F(ImageElementTimingTest, SVGImageRemoved) {
EXPECT_EQ(ImagesNotifiedSize(), 0u);
}
-TEST_F(ImageElementTimingTest, BackgroundImageRemoved) {
+TEST_P(ImageElementTimingTest, BackgroundImageRemoved) {
frame_test_helpers::LoadHTMLString(
web_view_helper_.GetWebView()->MainFrameImpl(), R"HTML(
<style>
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
index 6f8d03d3cda..eea55437e84 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/layout/layout_image_resource.h"
@@ -215,7 +216,8 @@ void ImagePaintTimingDetector::RecordImage(
const IntSize& intrinsic_size,
const ImageResourceContent& cached_image,
const PropertyTreeState& current_paint_chunk_properties,
- const StyleFetchedImage* style_image) {
+ const StyleFetchedImage* style_image,
+ const IntRect* image_border) {
Node* node = object.GetNode();
if (!node)
return;
@@ -234,7 +236,8 @@ void ImagePaintTimingDetector::RecordImage(
frame_view_->GetPaintTimingDetector().Visualizer()) {
FloatRect mapped_visual_rect =
frame_view_->GetPaintTimingDetector().CalculateVisualRect(
- object.FragmentsVisualRectBoundingBox(),
+ image_border ? *image_border
+ : object.FragmentsVisualRectBoundingBox(),
current_paint_chunk_properties);
visualizer->DumpImageDebuggingRect(object, mapped_visual_rect,
cached_image);
@@ -244,7 +247,8 @@ void ImagePaintTimingDetector::RecordImage(
if (is_recored_visible_image || !is_recording_)
return;
- IntRect visual_rect = object.FragmentsVisualRectBoundingBox();
+ IntRect visual_rect =
+ image_border ? *image_border : object.FragmentsVisualRectBoundingBox();
// Before the image resource starts loading, <img> has no size info. We wait
// until the size is known.
if (visual_rect.IsEmpty())
@@ -338,7 +342,7 @@ ImageRecord* ImageRecordsManager::FindLargestPaintCandidate() const {
return size_ordered_set_.begin()->get();
}
-void ImagePaintTimingDetector::Trace(blink::Visitor* visitor) {
+void ImagePaintTimingDetector::Trace(Visitor* visitor) {
visitor->Trace(frame_view_);
visitor->Trace(callback_manager_);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
index b18203fdb9e..29c490a6481 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
@@ -213,7 +213,8 @@ class CORE_EXPORT ImagePaintTimingDetector final
const IntSize& intrinsic_size,
const ImageResourceContent&,
const PropertyTreeState& current_paint_chunk_properties,
- const StyleFetchedImage*);
+ const StyleFetchedImage*,
+ const IntRect* image_border);
void NotifyImageFinished(const LayoutObject&, const ImageResourceContent*);
void OnPaintFinished();
void LayoutObjectWillBeDestroyed(const LayoutObject&);
@@ -236,7 +237,7 @@ class CORE_EXPORT ImagePaintTimingDetector final
// Return the candidate.
ImageRecord* UpdateCandidate();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
friend class LargestContentfulPaintCalculatorTest;
diff --git a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
index 6b606789d33..66125f8a9c2 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -25,7 +25,7 @@
#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
#include "third_party/skia/include/core/SkImage.h"
@@ -33,7 +33,25 @@
namespace blink {
-class ImagePaintTimingDetectorTest : public testing::Test {
+#define SIMPLE_IMAGE \
+ "url(data:image/gif;base64," \
+ "R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)"
+
+#define LARGE_IMAGE \
+ "url(data:image/gif;base64," \
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSF" \
+ "lzAAAN1wAADdcBQiibeAAAAb5JREFUOMulkr1KA0EQgGdvTwwnYmER0gQsrFKmSy+pLESw9Qm0" \
+ "F/ICNnba+h6iEOuAEWslKJKTOyJJvIT72d1xZuOFC0giOLA77O7Mt/PnNptN+I+49Xr9GhH3f3" \
+ "mb0v1ht9vtLAUYYw5ItkgDL3KyD8PhcLvdbl/WarXT3DjLMnAcR/f7/YfxeKwtgC5RKQVhGILW" \
+ "eg4hQ6hUKjWyucmhLFEUuWR3QYBWAZABQ9i5CCmXy16pVALP80BKaaG+70MQBLvzFMjRKKXh8j" \
+ "6FSYKF7ITdEWLa4/ktokN74wiqjSMpnVcbQZqmEJHz+ckeCPFjWKwULpyspAqhdXVXdcnZcPjs" \
+ "Ign+2BsVA8jVYuWlgJ3yBj0icgq2uoK+lg4t+ZvLomSKamSQ4AI5BcMADtMhyNoSgNIISUaFNt" \
+ "wlazcDcBc4gjjVwCWid2usCWroYEhnaqbzFJLUzAHIXRDChXCcQP8zhkSZ5eNLgHAUzwDcRu4C" \
+ "oIRn/wsGUQIIy4Vr9TH6SYFCNzw4nALn5627K4vIttOUOwfa5YnrDYzt/9OLv9I5l8kk5hZ3XL" \
+ "O20b7tbR7zHLy/BX8G0IeBEM7ZN1NGIaFUaKLgAAAAAElFTkSuQmCC)"
+
+class ImagePaintTimingDetectorTest : public testing::Test,
+ public PaintTestConfigurations {
public:
ImagePaintTimingDetectorTest()
: test_task_runner_(
@@ -152,8 +170,7 @@ class ImagePaintTimingDetectorTest : public testing::Test {
}
void UpdateAllLifecyclePhases() {
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
}
void UpdateAllLifecyclePhasesAndInvokeCallbackIfAny() {
@@ -177,8 +194,7 @@ class ImagePaintTimingDetectorTest : public testing::Test {
void SetChildBodyInnerHTML(const String& content) {
GetChildDocument()->SetBaseURLOverride(KURL("http://test.com"));
- GetChildDocument()->body()->SetInnerHTMLFromString(content,
- ASSERT_NO_EXCEPTION);
+ GetChildDocument()->body()->setInnerHTML(content, ASSERT_NO_EXCEPTION);
child_mock_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetChildPaintTimingDetector()
@@ -235,7 +251,13 @@ class ImagePaintTimingDetectorTest : public testing::Test {
To<SVGImageElement>(element)->SetImageForTest(content);
}
- void SimulateScroll() { GetPaintTimingDetector().NotifyScroll(kUserScroll); }
+ void SimulateScroll() {
+ GetPaintTimingDetector().NotifyScroll(mojom::blink::ScrollType::kUser);
+ }
+
+ void SimulateKeyUp() {
+ GetPaintTimingDetector().NotifyInputEvent(WebInputEvent::kKeyUp);
+ }
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
frame_test_helpers::WebViewHelper web_view_helper_;
@@ -266,7 +288,9 @@ class ImagePaintTimingDetectorTest : public testing::Test {
constexpr base::TimeDelta ImagePaintTimingDetectorTest::kQuantumOfTime;
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_NoImage) {
+INSTANTIATE_PAINT_TEST_SUITE_P(ImagePaintTimingDetectorTest);
+
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_NoImage) {
SetBodyInnerHTML(R"HTML(
<div></div>
)HTML");
@@ -274,7 +298,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_NoImage) {
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_OneImage) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_OneImage) {
SetBodyInnerHTML(R"HTML(
<img id="target"></img>
)HTML");
@@ -286,7 +310,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_OneImage) {
EXPECT_TRUE(record->loaded);
}
-TEST_F(ImagePaintTimingDetectorTest, InsertionOrderIsSecondaryRankingKey) {
+TEST_P(ImagePaintTimingDetectorTest, InsertionOrderIsSecondaryRankingKey) {
SetBodyInnerHTML(R"HTML(
)HTML");
@@ -311,7 +335,7 @@ TEST_F(ImagePaintTimingDetectorTest, InsertionOrderIsSecondaryRankingKey) {
DOMNodeIds::ExistingIdForNode(image1));
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_Candidate) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_Candidate) {
using trace_analyzer::Query;
trace_analyzer::Start("loading");
{
@@ -352,7 +376,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_Candidate) {
EXPECT_EQ(false, isOOPIF);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_NoCandidate) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_NoCandidate) {
using trace_analyzer::Query;
trace_analyzer::Start("*");
{
@@ -402,7 +426,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_TraceEvent_NoCandidate) {
}
}
-TEST_F(ImagePaintTimingDetectorTest, UpdatePerformanceTiming) {
+TEST_P(ImagePaintTimingDetectorTest, UpdatePerformanceTiming) {
EXPECT_EQ(GetPerformanceTiming().LargestImagePaintSize(), 0u);
EXPECT_EQ(GetPerformanceTiming().LargestImagePaint(), 0u);
SetBodyInnerHTML(R"HTML(
@@ -414,7 +438,7 @@ TEST_F(ImagePaintTimingDetectorTest, UpdatePerformanceTiming) {
EXPECT_GT(GetPerformanceTiming().LargestImagePaint(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
PerformanceTimingHasZeroTimeNonZeroSizeWhenTheLargestIsNotPainted) {
EXPECT_EQ(GetPerformanceTiming().LargestImagePaintSize(), 0u);
EXPECT_EQ(GetPerformanceTiming().LargestImagePaint(), 0u);
@@ -427,7 +451,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(GetPerformanceTiming().LargestImagePaint(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest, UpdatePerformanceTimingToZero) {
+TEST_P(ImagePaintTimingDetectorTest, UpdatePerformanceTimingToZero) {
SetBodyInnerHTML(R"HTML(
<img id="target"></img>
)HTML");
@@ -441,7 +465,7 @@ TEST_F(ImagePaintTimingDetectorTest, UpdatePerformanceTimingToZero) {
EXPECT_EQ(GetPerformanceTiming().LargestImagePaint(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_OpacityZero) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_OpacityZero) {
SetBodyInnerHTML(R"HTML(
<style>
img {
@@ -457,7 +481,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_OpacityZero) {
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_VisibilityHidden) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_VisibilityHidden) {
SetBodyInnerHTML(R"HTML(
<style>
img {
@@ -473,7 +497,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_VisibilityHidden) {
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_DisplayNone) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_DisplayNone) {
SetBodyInnerHTML(R"HTML(
<style>
img {
@@ -489,7 +513,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_DisplayNone) {
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_OpacityNonZero) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_OpacityNonZero) {
SetBodyInnerHTML(R"HTML(
<style>
img {
@@ -505,7 +529,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_OpacityNonZero) {
EXPECT_TRUE(record);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
IgnoreImageUntilInvalidatedRectSizeNonZero) {
SetBodyInnerHTML(R"HTML(
<img id="target"></img>
@@ -519,7 +543,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(CountVisibleImageRecords(), 1u);
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_Largest) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_Largest) {
SetBodyInnerHTML(R"HTML(
<style>img { display:block }</style>
<img id="smaller"></img>
@@ -537,7 +561,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_Largest) {
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
LargestImagePaint_IgnoreThoseOutsideViewport) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -554,7 +578,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
LargestImagePaint_UpdateOnRemovingTheLastImage) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
@@ -576,7 +600,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(LargestPaintStoredResult(), base::TimeTicks());
}
-TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_UpdateOnRemoving) {
+TEST_P(ImagePaintTimingDetectorTest, LargestImagePaint_UpdateOnRemoving) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
<img id="target1"></img>
@@ -608,7 +632,7 @@ TEST_F(ImagePaintTimingDetectorTest, LargestImagePaint_UpdateOnRemoving) {
EXPECT_EQ(first_largest_image_paint, LargestPaintStoredResult());
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
LargestImagePaint_NodeRemovedBetweenRegistrationAndInvocation) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
@@ -628,7 +652,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
RemoveRecordFromAllContainersAfterImageRemoval) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
@@ -644,8 +668,12 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(ContainerTotalSize(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
RemoveRecordFromAllContainersAfterInvisibleImageRemoved) {
+ // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
SetBodyInnerHTML(R"HTML(
<style>
#target {
@@ -673,12 +701,12 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(CountInvisibleRecords(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
RemoveRecordFromAllContainersAfterBackgroundImageRemoval) {
SetBodyInnerHTML(R"HTML(
<style>
#target {
- background-image: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==);
+ background-image: )HTML" SIMPLE_IMAGE R"HTML(;
}
</style>
<div id="parent">
@@ -695,7 +723,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(ContainerTotalSize(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
RemoveRecordFromAllContainersAfterImageRemovedAndCallbackInvoked) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
@@ -713,7 +741,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(ContainerTotalSize(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
LargestImagePaint_ReattachedNodeTreatedAsNew) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
@@ -756,7 +784,7 @@ TEST_F(ImagePaintTimingDetectorTest,
// This is to prove that a swap time is assigned only to nodes of the frame who
// register the swap time. In other words, swap time A should match frame A;
// swap time B should match frame B.
-TEST_F(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
+TEST_P(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
<img height="5" width="5" id="smaller"></img>
@@ -784,7 +812,7 @@ TEST_F(ImagePaintTimingDetectorTest, MatchSwapTimeToNodesOfDifferentFrames) {
EXPECT_NE(record1Time, record2->paint_time);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
LargestImagePaint_UpdateResultWhenLargestChanged) {
base::TimeTicks time1 = test_task_runner_->NowTicks();
SetBodyInnerHTML(R"HTML(
@@ -808,7 +836,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_GE(time3, result2);
}
-TEST_F(ImagePaintTimingDetectorTest, OneSwapPromiseForOneFrame) {
+TEST_P(ImagePaintTimingDetectorTest, OneSwapPromiseForOneFrame) {
SetBodyInnerHTML(R"HTML(
<style>img { display:block }</style>
<div id="parent">
@@ -840,7 +868,7 @@ TEST_F(ImagePaintTimingDetectorTest, OneSwapPromiseForOneFrame) {
EXPECT_FALSE(record->paint_time.is_null());
}
-TEST_F(ImagePaintTimingDetectorTest, VideoImage) {
+TEST_P(ImagePaintTimingDetectorTest, VideoImage) {
SetBodyInnerHTML(R"HTML(
<video id="target"></video>
)HTML");
@@ -854,17 +882,15 @@ TEST_F(ImagePaintTimingDetectorTest, VideoImage) {
EXPECT_TRUE(record->loaded);
}
-TEST_F(ImagePaintTimingDetectorTest, VideoImage_ImageNotLoaded) {
- SetBodyInnerHTML(R"HTML(
- <video id="target"></video>
- )HTML");
+TEST_P(ImagePaintTimingDetectorTest, VideoImage_ImageNotLoaded) {
+ SetBodyInnerHTML("<video id='target'></video>");
UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
ImageRecord* record = FindLargestPaintCandidate();
EXPECT_FALSE(record);
}
-TEST_F(ImagePaintTimingDetectorTest, SVGImage) {
+TEST_P(ImagePaintTimingDetectorTest, SVGImage) {
SetBodyInnerHTML(R"HTML(
<svg>
<image id="target" width="10" height="10"/>
@@ -880,28 +906,26 @@ TEST_F(ImagePaintTimingDetectorTest, SVGImage) {
EXPECT_TRUE(record->loaded);
}
-TEST_F(ImagePaintTimingDetectorTest, BackgroundImage) {
+TEST_P(ImagePaintTimingDetectorTest, BackgroundImage) {
SetBodyInnerHTML(R"HTML(
<style>
div {
- background-image: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==);
+ background-image: )HTML" SIMPLE_IMAGE R"HTML(;
}
</style>
- <div>
- place-holder
- </div>
+ <div>place-holder</div>
)HTML");
ImageRecord* record = FindLargestPaintCandidate();
EXPECT_TRUE(record);
EXPECT_EQ(CountVisibleImageRecords(), 1u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
BackgroundImageAndLayoutImageTrackedDifferently) {
SetBodyInnerHTML(R"HTML(
<style>
img {
- background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAb5JREFUOMulkr1KA0EQgGdvTwwnYmER0gQsrFKmSy+pLESw9Qm0F/ICNnba+h6iEOuAEWslKJKTOyJJvIT72d1xZuOFC0giOLA77O7Mt/PnNptN+I+49Xr9GhH3f3mb0v1ht9vtLAUYYw5ItkgDL3KyD8PhcLvdbl/WarXT3DjLMnAcR/f7/YfxeKwtgC5RKQVhGILWeg4hQ6hUKjWyucmhLFEUuWR3QYBWAZABQ9i5CCmXy16pVALP80BKaaG+70MQBLvzFMjRKKXh8j6FSYKF7ITdEWLa4/ktokN74wiqjSMpnVcbQZqmEJHz+ckeCPFjWKwULpyspAqhdXVXdcnZcPjsIgn+2BsVA8jVYuWlgJ3yBj0icgq2uoK+lg4t+ZvLomSKamSQ4AI5BcMADtMhyNoSgNIISUaFNtwlazcDcBc4gjjVwCWid2usCWroYEhnaqbzFJLUzAHIXRDChXCcQP8zhkSZ5eNLgHAUzwDcRu4CoIRn/wsGUQIIy4Vr9TH6SYFCNzw4nALn5627K4vIttOUOwfa5YnrDYzt/9OLv9I5l8kk5hZ3XLO20b7tbR7zHLy/BX8G0IeBEM7ZN1NGIaFUaKLgAAAAAElFTkSuQmCC);
+ background-image: )HTML" LARGE_IMAGE R"HTML(;
}
</style>
<img id="target">
@@ -916,31 +940,17 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(record->first_size, 1u);
}
-TEST_F(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreBody) {
- SetBodyInnerHTML(R"HTML(
- <style>
- body {
- background-image: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==);
- }
- </style>
- )HTML");
+TEST_P(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreBody) {
+ SetBodyInnerHTML("<style>body { background-image: " SIMPLE_IMAGE "}</style>");
EXPECT_EQ(CountVisibleImageRecords(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreHtml) {
- SetBodyInnerHTML(R"HTML(
- <html>
- <style>
- html {
- background-image: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==);
- }
- </style>
- </html>
- )HTML");
+TEST_P(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreHtml) {
+ SetBodyInnerHTML("<style>html { background-image: " SIMPLE_IMAGE "}</style>");
EXPECT_EQ(CountVisibleImageRecords(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreGradient) {
+TEST_P(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreGradient) {
SetBodyInnerHTML(R"HTML(
<style>
div {
@@ -956,15 +966,14 @@ TEST_F(ImagePaintTimingDetectorTest, BackgroundImage_IgnoreGradient) {
// We put two background images in the same object, and test whether FCP++ can
// find two different images.
-TEST_F(ImagePaintTimingDetectorTest, BackgroundImageTrackedDifferently) {
+TEST_P(ImagePaintTimingDetectorTest, BackgroundImageTrackedDifferently) {
SetBodyInnerHTML(R"HTML(
<style>
#d {
width: 50px;
height: 50px;
background-image:
- url("data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="),
- url("data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAb5JREFUOMulkr1KA0EQgGdvTwwnYmER0gQsrFKmSy+pLESw9Qm0F/ICNnba+h6iEOuAEWslKJKTOyJJvIT72d1xZuOFC0giOLA77O7Mt/PnNptN+I+49Xr9GhH3f3mb0v1ht9vtLAUYYw5ItkgDL3KyD8PhcLvdbl/WarXT3DjLMnAcR/f7/YfxeKwtgC5RKQVhGILWeg4hQ6hUKjWyucmhLFEUuWR3QYBWAZABQ9i5CCmXy16pVALP80BKaaG+70MQBLvzFMjRKKXh8j6FSYKF7ITdEWLa4/ktokN74wiqjSMpnVcbQZqmEJHz+ckeCPFjWKwULpyspAqhdXVXdcnZcPjsIgn+2BsVA8jVYuWlgJ3yBj0icgq2uoK+lg4t+ZvLomSKamSQ4AI5BcMADtMhyNoSgNIISUaFNtwlazcDcBc4gjjVwCWid2usCWroYEhnaqbzFJLUzAHIXRDChXCcQP8zhkSZ5eNLgHAUzwDcRu4CoIRn/wsGUQIIy4Vr9TH6SYFCNzw4nALn5627K4vIttOUOwfa5YnrDYzt/9OLv9I5l8kk5hZ3XLO20b7tbR7zHLy/BX8G0IeBEM7ZN1NGIaFUaKLgAAAAAElFTkSuQmCC");
+ )HTML" SIMPLE_IMAGE "," LARGE_IMAGE R"HTML(;
}
</style>
<div id="d"></div>
@@ -972,7 +981,7 @@ TEST_F(ImagePaintTimingDetectorTest, BackgroundImageTrackedDifferently) {
EXPECT_EQ(CountVisibleImageRecords(), 2u);
}
-TEST_F(ImagePaintTimingDetectorTest, DeactivateAfterUserInput) {
+TEST_P(ImagePaintTimingDetectorTest, DeactivateAfterUserInput) {
SetBodyInnerHTML(R"HTML(
<div id="parent">
<img id="target"></img>
@@ -984,7 +993,19 @@ TEST_F(ImagePaintTimingDetectorTest, DeactivateAfterUserInput) {
EXPECT_FALSE(GetPaintTimingDetector().GetImagePaintTimingDetector());
}
-TEST_F(ImagePaintTimingDetectorTest, NullTimeNoCrash) {
+TEST_P(ImagePaintTimingDetectorTest, ContinueAfterKeyUp) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="parent">
+ <img id="target"></img>
+ </div>
+ )HTML");
+ SimulateKeyUp();
+ SetImageAndPaint("target", 5, 5);
+ UpdateAllLifecyclePhasesAndInvokeCallbackIfAny();
+ EXPECT_TRUE(GetPaintTimingDetector().GetImagePaintTimingDetector());
+}
+
+TEST_P(ImagePaintTimingDetectorTest, NullTimeNoCrash) {
SetBodyInnerHTML(R"HTML(
<img id="target"></img>
)HTML");
@@ -993,7 +1014,7 @@ TEST_F(ImagePaintTimingDetectorTest, NullTimeNoCrash) {
UpdateCandidate();
}
-TEST_F(ImagePaintTimingDetectorTest, Iframe) {
+TEST_P(ImagePaintTimingDetectorTest, Iframe) {
SetBodyInnerHTML(R"HTML(
<iframe width=100px height=100px></iframe>
)HTML");
@@ -1013,7 +1034,7 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe) {
EXPECT_EQ(image->first_size, 25ul);
}
-TEST_F(ImagePaintTimingDetectorTest, Iframe_ClippedByMainFrameViewport) {
+TEST_P(ImagePaintTimingDetectorTest, Iframe_ClippedByMainFrameViewport) {
SetBodyInnerHTML(R"HTML(
<style>
#f { margin-top: 1234567px }
@@ -1031,7 +1052,7 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe_ClippedByMainFrameViewport) {
EXPECT_EQ(CountVisibleImageRecords(), 0u);
}
-TEST_F(ImagePaintTimingDetectorTest, Iframe_HalfClippedByMainFrameViewport) {
+TEST_P(ImagePaintTimingDetectorTest, Iframe_HalfClippedByMainFrameViewport) {
SetBodyInnerHTML(R"HTML(
<style>
#f { margin-left: -5px; }
@@ -1052,7 +1073,7 @@ TEST_F(ImagePaintTimingDetectorTest, Iframe_HalfClippedByMainFrameViewport) {
EXPECT_LT(image->first_size, 100ul);
}
-TEST_F(ImagePaintTimingDetectorTest, SameSizeShouldNotBeIgnored) {
+TEST_P(ImagePaintTimingDetectorTest, SameSizeShouldNotBeIgnored) {
SetBodyInnerHTML(R"HTML(
<style>img { display:block }</style>
<img id='1'></img>
@@ -1066,7 +1087,7 @@ TEST_F(ImagePaintTimingDetectorTest, SameSizeShouldNotBeIgnored) {
EXPECT_EQ(CountRankingSetRecords(), 3u);
}
-TEST_F(ImagePaintTimingDetectorTest, UseIntrinsicSizeIfSmaller_Image) {
+TEST_P(ImagePaintTimingDetectorTest, UseIntrinsicSizeIfSmaller_Image) {
SetBodyInnerHTML(R"HTML(
<img height="300" width="300" display="block" id="target">
</img>
@@ -1078,7 +1099,7 @@ TEST_F(ImagePaintTimingDetectorTest, UseIntrinsicSizeIfSmaller_Image) {
EXPECT_EQ(record->first_size, 25u);
}
-TEST_F(ImagePaintTimingDetectorTest, NotUseIntrinsicSizeIfLarger_Image) {
+TEST_P(ImagePaintTimingDetectorTest, NotUseIntrinsicSizeIfLarger_Image) {
SetBodyInnerHTML(R"HTML(
<img height="1" width="1" display="block" id="target">
</img>
@@ -1090,14 +1111,14 @@ TEST_F(ImagePaintTimingDetectorTest, NotUseIntrinsicSizeIfLarger_Image) {
EXPECT_EQ(record->first_size, 1u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
UseIntrinsicSizeIfSmaller_BackgroundImage) {
SetBodyInnerHTML(R"HTML(
<style>
#d {
width: 50px;
height: 50px;
- background-image: url("data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==");
+ background-image: )HTML" SIMPLE_IMAGE R"HTML(;
}
</style>
<div id="d"></div>
@@ -1107,7 +1128,7 @@ TEST_F(ImagePaintTimingDetectorTest,
EXPECT_EQ(record->first_size, 1u);
}
-TEST_F(ImagePaintTimingDetectorTest,
+TEST_P(ImagePaintTimingDetectorTest,
NotUseIntrinsicSizeIfLarger_BackgroundImage) {
// The image is in 16x16.
SetBodyInnerHTML(R"HTML(
@@ -1115,7 +1136,7 @@ TEST_F(ImagePaintTimingDetectorTest,
#d {
width: 5px;
height: 5px;
- background-image: url("data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAb5JREFUOMulkr1KA0EQgGdvTwwnYmER0gQsrFKmSy+pLESw9Qm0F/ICNnba+h6iEOuAEWslKJKTOyJJvIT72d1xZuOFC0giOLA77O7Mt/PnNptN+I+49Xr9GhH3f3mb0v1ht9vtLAUYYw5ItkgDL3KyD8PhcLvdbl/WarXT3DjLMnAcR/f7/YfxeKwtgC5RKQVhGILWeg4hQ6hUKjWyucmhLFEUuWR3QYBWAZABQ9i5CCmXy16pVALP80BKaaG+70MQBLvzFMjRKKXh8j6FSYKF7ITdEWLa4/ktokN74wiqjSMpnVcbQZqmEJHz+ckeCPFjWKwULpyspAqhdXVXdcnZcPjsIgn+2BsVA8jVYuWlgJ3yBj0icgq2uoK+lg4t+ZvLomSKamSQ4AI5BcMADtMhyNoSgNIISUaFNtwlazcDcBc4gjjVwCWid2usCWroYEhnaqbzFJLUzAHIXRDChXCcQP8zhkSZ5eNLgHAUzwDcRu4CoIRn/wsGUQIIy4Vr9TH6SYFCNzw4nALn5627K4vIttOUOwfa5YnrDYzt/9OLv9I5l8kk5hZ3XLO20b7tbR7zHLy/BX8G0IeBEM7ZN1NGIaFUaKLgAAAAAElFTkSuQmCC");
+ background-image: )HTML" LARGE_IMAGE R"HTML(;
}
</style>
<div id="d"></div>
diff --git a/chromium/third_party/blink/renderer/core/paint/image_painter.cc b/chromium/third_party/blink/renderer/core/paint/image_painter.cc
index be0a21026fb..86470ade240 100644
--- a/chromium/third_party/blink/renderer/core/paint/image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/image_painter.cc
@@ -61,7 +61,7 @@ bool CheckForOversizedImagesPolicy(const LayoutImage& layout_image,
cached_image ? cached_image->Url().GetString() : g_empty_string;
return !layout_image.GetDocument().IsFeatureEnabled(
- mojom::FeaturePolicyFeature::kOversizedImages,
+ mojom::blink::DocumentPolicyFeature::kOversizedImages,
blink::PolicyValue(
std::max(downscale_ratio_width, downscale_ratio_height),
blink::mojom::PolicyValueType::kDecDouble),
@@ -142,7 +142,7 @@ void ImagePainter::PaintReplaced(const PaintInfo& paint_info,
if (content_size.IsEmpty())
return;
} else {
- if (paint_info.phase == PaintPhase::kSelection)
+ if (paint_info.phase == PaintPhase::kSelectionDragImage)
return;
if (content_size.Width() <= 2 || content_size.Height() <= 2)
return;
@@ -187,8 +187,8 @@ void ImagePainter::PaintReplaced(const PaintInfo& paint_info,
void ImagePainter::PaintIntoRect(GraphicsContext& context,
const PhysicalRect& dest_rect,
const PhysicalRect& content_rect) {
- if (!layout_image_.ImageResource()->HasImage() ||
- layout_image_.ImageResource()->ErrorOccurred())
+ const LayoutImageResource& image_resource = *layout_image_.ImageResource();
+ if (!image_resource.HasImage() || image_resource.ErrorOccurred())
return; // FIXME: should we just ASSERT these conditions? (audit all
// callers).
@@ -197,11 +197,14 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
return;
scoped_refptr<Image> image =
- layout_image_.ImageResource()->GetImage(pixel_snapped_dest_rect.Size());
+ image_resource.GetImage(FloatSize(dest_rect.size));
if (!image || image->IsNull())
return;
- FloatRect src_rect = FloatRect(image->Rect());
+ // Do not respect the image orientation when computing the source rect. It is
+ // in the un-orientated dimensions.
+ FloatRect src_rect(FloatPoint(),
+ image->SizeAsFloat(kDoNotRespectImageOrientation));
// If the content rect requires clipping, adjust |srcRect| and
// |pixelSnappedDestRect| over using a clip.
if (!content_rect.Contains(dest_rect)) {
@@ -249,17 +252,18 @@ void ImagePainter::PaintIntoRect(GraphicsContext& context,
layout_image_.StyleRef().HasFilterInducingProperty(),
SkBlendMode::kSrcOver,
LayoutObject::ShouldRespectImageOrientation(&layout_image_));
+
+ ImageResourceContent* image_content = image_resource.CachedImage();
if ((IsA<HTMLImageElement>(node) || IsA<HTMLVideoElement>(node)) &&
- !context.ContextDisabled() && layout_image_.CachedImage() &&
- layout_image_.CachedImage()->IsLoaded()) {
+ image_content && image_content->IsLoaded()) {
LocalDOMWindow* window = layout_image_.GetDocument().domWindow();
DCHECK(window);
ImageElementTiming::From(*window).NotifyImagePainted(
- &layout_image_, layout_image_.CachedImage(),
+ &layout_image_, image_content,
context.GetPaintController().CurrentPaintChunkProperties());
}
PaintTimingDetector::NotifyImagePaint(
- layout_image_, image->Size(), layout_image_.CachedImage(),
+ layout_image_, image->Size(), image_content,
context.GetPaintController().CurrentPaintChunkProperties());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
index 0dc82e10ad0..4c826eadfa4 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
+++ b/chromium/third_party/blink/renderer/core/paint/inline_box_painter_base.h
@@ -84,8 +84,8 @@ class InlineBoxPainterBase {
bool object_has_multiple_boxes) const = 0;
const ImageResourceObserver& image_observer_;
- Member<const Document> document_;
- Member<Node> node_;
+ const Document* document_;
+ Node* node_;
// Style for the corresponding node.
const ComputedStyle& style_;
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
index 4c14b9f3a1c..36a2191b612 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
@@ -15,7 +15,6 @@
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
namespace blink {
@@ -186,12 +185,12 @@ void InlineFlowBoxPainter::PaintBackgroundBorderShadow(
const LayoutPoint& paint_offset) {
DCHECK(paint_info.phase == PaintPhase::kForeground);
- RecordHitTestData(paint_info, paint_offset);
-
if (inline_flow_box_.GetLineLayoutItem().StyleRef().Visibility() !=
EVisibility::kVisible)
return;
+ RecordHitTestData(paint_info, paint_offset);
+
// You can use p::first-line to specify a background. If so, the root line
// boxes for a line may actually have to paint a background.
LayoutObject* inline_flow_box_layout_object =
@@ -340,17 +339,11 @@ void InlineFlowBoxPainter::RecordHitTestData(const PaintInfo& paint_info,
LayoutObject* layout_object =
LineLayoutAPIShim::LayoutObjectFrom(inline_flow_box_.GetLineLayoutItem());
- // If an object is not visible, it does not participate in hit testing.
- if (layout_object->StyleRef().Visibility() != EVisibility::kVisible)
- return;
-
- auto touch_action = layout_object->EffectiveAllowedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
- return;
+ DCHECK_EQ(layout_object->StyleRef().Visibility(), EVisibility::kVisible);
- HitTestDisplayItem::Record(
- paint_info.context, inline_flow_box_,
- HitTestRect(AdjustedPaintRect(paint_offset), touch_action));
+ paint_info.context.GetPaintController().RecordHitTestData(
+ inline_flow_box_, PixelSnappedIntRect(AdjustedPaintRect(paint_offset)),
+ layout_object->EffectiveAllowedTouchAction());
}
void InlineFlowBoxPainter::PaintNormalBoxShadow(const PaintInfo& info,
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.h b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.h
index 9b239f13267..f4d6a2831bd 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/inline_flow_box_painter.h
@@ -77,9 +77,9 @@ class InlineFlowBoxPainter : public InlineBoxPainterBase {
LayoutRect AdjustedPaintRect(const LayoutPoint& paint_offset) const;
- // Paint a hit test display item and record hit test data. This should be
- // called when painting the background even if there is no other painted
- // content.
+ // Expands the bounds of the current paint chunk for hit test, and records
+ // special touch action if any. This should be called in the background paint
+ // phase even if there is no other painted content.
void RecordHitTestData(const PaintInfo&, const LayoutPoint& paint_offset);
const InlineFlowBox& inline_flow_box_;
diff --git a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
index 8f5cb403a0f..065c32ba2e8 100644
--- a/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/inline_text_box_painter.cc
@@ -149,7 +149,7 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
bool have_selection = !is_printing &&
paint_info.phase != PaintPhase::kTextClip &&
inline_text_box_.IsSelected();
- if (!have_selection && paint_info.phase == PaintPhase::kSelection) {
+ if (!have_selection && paint_info.phase == PaintPhase::kSelectionDragImage) {
// When only painting the selection, don't bother to paint if there is none.
return;
}
@@ -264,7 +264,8 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
inline_text_box_.GetLineLayoutItem().GetDocument(), style_to_use,
inline_text_box_.GetLineLayoutItem().GetNode(), have_selection,
paint_info, text_style);
- bool paint_selected_text_only = (paint_info.phase == PaintPhase::kSelection);
+ bool paint_selected_text_only =
+ (paint_info.phase == PaintPhase::kSelectionDragImage);
bool paint_selected_text_separately =
!paint_selected_text_only && text_style != selection_style;
@@ -280,7 +281,7 @@ void InlineTextBoxPainter::Paint(const PaintInfo& paint_info,
// 1. Paint backgrounds behind text if needed. Examples of such backgrounds
// include selection and composition highlights.
- if (paint_info.phase != PaintPhase::kSelection &&
+ if (paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip && !is_printing) {
PaintDocumentMarkers(markers_to_paint, paint_info, box_origin, style_to_use,
font, DocumentMarkerPaintPhase::kBackground);
diff --git a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.cc b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.cc
index d5ab8898d63..dd110c79c0b 100644
--- a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.cc
@@ -68,11 +68,13 @@ void LargestContentfulPaintCalculator::UpdateLargestContentPaintIfNeeded(
bool text_has_changed = false;
if (largest_image.has_value()) {
image_has_changed = HasLargestImageChanged(largest_image_, *largest_image);
- OnLargestImageUpdated(*largest_image);
+ if (image_has_changed)
+ OnLargestImageUpdated(*largest_image);
}
if (largest_text.has_value()) {
text_has_changed = HasLargestTextChanged(largest_text_, *largest_text);
- OnLargestTextUpdated(*largest_text);
+ if (text_has_changed)
+ OnLargestTextUpdated(*largest_text);
}
// If |largest_image| does not have value, the detector may have been
// destroyed. In this case, keep using its last candidate for comparison with
@@ -121,17 +123,23 @@ void LargestContentfulPaintCalculator::UpdateLargestContentfulPaint(
return;
const KURL& url = cached_image->Url();
- auto* document = window_performance_->GetExecutionContext();
- bool expose_paint_time_to_api = true;
- bool response_tainting_not_basic = false;
- bool tainted_origin_flag = false;
- if (!url.ProtocolIsData() &&
- (!document ||
- !Performance::PassesTimingAllowCheck(
- cached_image->GetResponse(), cached_image->GetResponse(),
- *document->GetSecurityOrigin(), document,
- &response_tainting_not_basic, &tainted_origin_flag))) {
- expose_paint_time_to_api = false;
+ bool expose_paint_time_to_api = url.ProtocolIsData();
+ // Use TimingAllowPassed() if possible, see comment in ImageElementTiming.
+ if (!expose_paint_time_to_api) {
+ if (RuntimeEnabledFeatures::OutOfBlinkCorsEnabled()) {
+ expose_paint_time_to_api =
+ cached_image->GetResponse().TimingAllowPassed();
+ } else {
+ auto* document = window_performance_->GetExecutionContext();
+ bool response_tainting_not_basic = false;
+ bool tainted_origin_flag = false;
+ expose_paint_time_to_api =
+ document &&
+ Performance::PassesTimingAllowCheck(
+ cached_image->GetResponse(), cached_image->GetResponse(),
+ *document->GetSecurityOrigin(), document,
+ &response_tainting_not_basic, &tainted_origin_flag);
+ }
}
const String& image_url =
url.ProtocolIsData()
diff --git a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h
index 72de5f84b10..45d35a591a0 100644
--- a/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h
+++ b/chromium/third_party/blink/renderer/core/paint/largest_contentful_paint_calculator.h
@@ -23,7 +23,7 @@ class CORE_EXPORT LargestContentfulPaintCalculator final
base::Optional<base::WeakPtr<TextRecord>> largest_text,
base::Optional<const ImageRecord*> largest_image);
- void Trace(blink::Visitor* visitor);
+ void Trace(Visitor* visitor);
private:
friend class LargestContentfulPaintCalculatorTest;
diff --git a/chromium/third_party/blink/renderer/core/paint/line_box_list_painter.cc b/chromium/third_party/blink/renderer/core/paint/line_box_list_painter.cc
index 3df1a8f2a29..1bbdc7dcc45 100644
--- a/chromium/third_party/blink/renderer/core/paint/line_box_list_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/line_box_list_painter.cc
@@ -74,9 +74,7 @@ void BuildBackplate(const InlineFlowBox* box,
}
}
-} // anonymous namespace
-
-static void AddURLRectsForInlineChildrenRecursively(
+void AddURLRectsForInlineChildrenRecursively(
const LayoutObject& layout_object,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
@@ -90,6 +88,8 @@ static void AddURLRectsForInlineChildrenRecursively(
}
}
+} // anonymous namespace
+
bool LineBoxListPainter::ShouldPaint(const LayoutBoxModelObject& layout_object,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) const {
@@ -100,12 +100,6 @@ bool LineBoxListPainter::ShouldPaint(const LayoutBoxModelObject& layout_object,
DCHECK(layout_object.IsLayoutBlock() ||
(layout_object.IsLayoutInline() && layout_object.HasLayer()));
- if (paint_info.phase == PaintPhase::kForeground &&
- paint_info.ShouldAddUrlMetadata()) {
- AddURLRectsForInlineChildrenRecursively(layout_object, paint_info,
- paint_offset);
- }
-
// If we have no lines then we have no work to do.
if (!line_box_list_.First())
return false;
@@ -123,11 +117,17 @@ void LineBoxListPainter::Paint(const LayoutBoxModelObject& layout_object,
const PhysicalOffset& paint_offset) const {
// Only paint during the foreground/selection phases.
if (paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelection &&
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip &&
paint_info.phase != PaintPhase::kMask)
return;
+ if (paint_info.phase == PaintPhase::kForeground &&
+ paint_info.ShouldAddUrlMetadata()) {
+ AddURLRectsForInlineChildrenRecursively(layout_object, paint_info,
+ paint_offset);
+ }
+
if (!ShouldPaint(layout_object, paint_info, paint_offset))
return;
@@ -158,8 +158,9 @@ void LineBoxListPainter::PaintBackplate(
const LayoutBoxModelObject& layout_object,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) const {
- if (paint_info.phase != PaintPhase::kForcedColorsModeBackplate ||
- !ShouldPaint(layout_object, paint_info, paint_offset))
+ DCHECK_EQ(paint_info.phase, PaintPhase::kForcedColorsModeBackplate);
+
+ if (!ShouldPaint(layout_object, paint_info, paint_offset))
return;
// Only paint backplates behind text when forced-color-adjust is auto.
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index 78ef41eddaa..c67909af9aa 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -33,7 +33,6 @@
#include "cc/layers/picture_layer.h"
#include "cc/paint/display_item_list.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_float_point.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/web/blink.h"
@@ -47,6 +46,8 @@
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
@@ -112,6 +113,8 @@ LinkHighlightImpl::LinkHighlightImpl(Node* node)
EffectPaintPropertyNode::Root(),
LinkHighlightEffectNodeState(kStartOpacity, element_id_));
+ DCHECK(GetLayoutObject());
+ GetLayoutObject()->SetNeedsPaintPropertyUpdate();
SetPaintArtifactCompositorNeedsUpdate();
#if DCHECK_IS_ON()
@@ -132,7 +135,7 @@ void LinkHighlightImpl::ReleaseResources() {
if (!node_)
return;
- if (auto* layout_object = node_->GetLayoutObject())
+ if (auto* layout_object = GetLayoutObject())
layout_object->SetNeedsPaintPropertyUpdate();
SetPaintArtifactCompositorNeedsUpdate();
@@ -142,7 +145,6 @@ void LinkHighlightImpl::ReleaseResources() {
LinkHighlightImpl::LinkHighlightFragment::LinkHighlightFragment() {
layer_ = cc::PictureLayer::Create(this);
- layer_->SetTransformOrigin(FloatPoint3D());
layer_->SetIsDrawable(true);
layer_->SetOpacity(kStartOpacity);
}
@@ -233,17 +235,15 @@ void LinkHighlightImpl::NotifyAnimationFinished(double, int) {
}
void LinkHighlightImpl::UpdateBeforePrePaint() {
- if (!node_ || !node_->GetLayoutObject() ||
- node_->GetLayoutObject()->GetFrameView()->ShouldThrottleRendering())
+ auto* object = GetLayoutObject();
+ if (!object || object->GetFrameView()->ShouldThrottleRendering())
ReleaseResources();
}
void LinkHighlightImpl::UpdateAfterPrePaint() {
- if (!node_)
+ auto* object = GetLayoutObject();
+ if (!object)
return;
-
- const auto* object = node_->GetLayoutObject();
- DCHECK(object);
DCHECK(!object->GetFrameView()->ShouldThrottleRendering());
size_t fragment_count = 0;
@@ -262,15 +262,12 @@ CompositorAnimation* LinkHighlightImpl::GetCompositorAnimation() const {
}
void LinkHighlightImpl::Paint(GraphicsContext& context) {
- if (!node_)
+ auto* object = GetLayoutObject();
+ if (!object)
return;
- const auto* object = node_->GetLayoutObject();
- // TODO(crbug.com/1016587): Change the CHECKs to DCHECKs after we address
- // the cause of the bug.
- CHECK(object);
- CHECK(object->GetFrameView());
- CHECK(!object->GetFrameView()->ShouldThrottleRendering());
+ DCHECK(object->GetFrameView());
+ DCHECK(!object->GetFrameView()->ShouldThrottleRendering());
static const FloatSize rect_rounding_radii(3, 3);
auto color = object->StyleRef().TapHighlightColor();
@@ -279,7 +276,6 @@ void LinkHighlightImpl::Paint(GraphicsContext& context) {
// otherwise we may sometimes get a chain of adjacent boxes (e.g. for text
// nodes) which end up looking like sausage links: these should ideally be
// merged into a single rect before creating the path.
- CHECK(node_->GetDocument().GetSettings());
bool use_rounded_rects = !node_->GetDocument()
.GetSettings()
->GetMockGestureTapHighlightsEnabled() &&
@@ -293,6 +289,20 @@ void LinkHighlightImpl::Paint(GraphicsContext& context) {
if (rects.size() > 1)
use_rounded_rects = false;
+ // TODO(yosin): We should remove following if-statement once we release
+ // NGFragmentItem to renderer rounded rect even if nested inline, e.g.
+ // <a>ABC<b>DEF</b>GHI</a>.
+ // See gesture-tapHighlight-simple-nested.html
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
+ use_rounded_rects && object->IsLayoutInline()) {
+ NGInlineCursor cursor;
+ cursor.MoveTo(*object);
+ // When |LayoutInline| has more than one children, we render square
+ // rectangle as |NGPaintFragment|.
+ if (cursor && cursor.CurrentItem()->DescendantsCount() > 2)
+ use_rounded_rects = false;
+ }
+
Path new_path;
for (auto& rect : rects) {
FloatRect snapped_rect(PixelSnappedIntRect(rect));
@@ -302,7 +312,7 @@ void LinkHighlightImpl::Paint(GraphicsContext& context) {
new_path.AddRect(snapped_rect);
}
- CHECK_LT(index, fragments_.size());
+ DCHECK_LT(index, fragments_.size());
auto& link_highlight_fragment = fragments_[index];
link_highlight_fragment.SetColor(color);
@@ -310,7 +320,7 @@ void LinkHighlightImpl::Paint(GraphicsContext& context) {
new_path.Translate(-ToFloatSize(bounding_rect.Location()));
auto* layer = link_highlight_fragment.Layer();
- CHECK(layer);
+ DCHECK(layer);
if (link_highlight_fragment.GetPath() != new_path) {
link_highlight_fragment.SetPath(new_path);
layer->SetBounds(gfx::Size(EnclosingIntRect(bounding_rect).Size()));
@@ -324,7 +334,7 @@ void LinkHighlightImpl::Paint(GraphicsContext& context) {
property_tree_state.SetEffect(Effect());
RecordForeignLayer(context, debug_name_client,
DisplayItem::kForeignLayerLinkHighlight, layer,
- bounding_rect.Location(), property_tree_state);
+ bounding_rect.Location(), &property_tree_state);
}
DCHECK_EQ(index, fragments_.size());
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
index 7d32caec420..d1acdedd830 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl.h
@@ -30,6 +30,7 @@
#include "cc/layers/content_layer_client.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_client.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_delegate.h"
@@ -48,7 +49,6 @@ namespace blink {
class EffectPaintPropertyNode;
class GraphicsContext;
-class Node;
class CORE_EXPORT LinkHighlightImpl final : public CompositorAnimationDelegate,
public CompositorAnimationClient {
@@ -66,7 +66,9 @@ class CORE_EXPORT LinkHighlightImpl final : public CompositorAnimationDelegate,
// CompositorAnimationClient implementation.
CompositorAnimation* GetCompositorAnimation() const override;
- Node* GetNode() const { return node_; }
+ LayoutObject* GetLayoutObject() const {
+ return node_ ? node_->GetLayoutObject() : nullptr;
+ }
CompositorElementId ElementIdForTesting() const { return element_id_; }
@@ -111,7 +113,7 @@ class CORE_EXPORT LinkHighlightImpl final : public CompositorAnimationDelegate,
};
Vector<LinkHighlightFragment> fragments_;
- Persistent<Node> node_;
+ WeakPersistent<Node> node_;
std::unique_ptr<CompositorAnimation> compositor_animation_;
scoped_refptr<EffectPaintPropertyNode> effect_;
diff --git a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
index 3b0ff3bb636..c7cb2458cb9 100644
--- a/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -30,8 +30,7 @@
#include "cc/layers/picture_layer.h"
#include "cc/trees/layer_tree_host.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_float_point.h"
-#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
#include "third_party/blink/public/web/web_frame.h"
@@ -104,7 +103,7 @@ class LinkHighlightImplTest : public testing::Test,
void UpdateAllLifecyclePhases() {
web_view_helper_.GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
+ DocumentUpdateReason::kTest);
}
LinkHighlight& GetLinkHighlight() {
@@ -141,14 +140,14 @@ TEST_P(LinkHighlightImplTest, verifyWebViewImplIntegration) {
// The coordinates below are linked to absolute positions in the referenced
// .html file.
- touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 20));
ASSERT_TRUE(web_view_impl->BestTapNode(GetTargetedEvent(touch_event)));
- touch_event.SetPositionInWidget(WebFloatPoint(20, 40));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 40));
EXPECT_FALSE(web_view_impl->BestTapNode(GetTargetedEvent(touch_event)));
- touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 20));
// Shouldn't crash.
web_view_impl->EnableTapHighlightAtPoint(GetTargetedEvent(touch_event));
@@ -158,7 +157,7 @@ TEST_P(LinkHighlightImplTest, verifyWebViewImplIntegration) {
EXPECT_TRUE(highlight->LayerForTesting(0));
// Find a target inside a scrollable div
- touch_event.SetPositionInWidget(WebFloatPoint(20, 100));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 100));
web_view_impl->EnableTapHighlightAtPoint(GetTargetedEvent(touch_event));
ASSERT_TRUE(highlight);
@@ -167,11 +166,11 @@ TEST_P(LinkHighlightImplTest, verifyWebViewImplIntegration) {
// Don't highlight if no "hand cursor"
touch_event.SetPositionInWidget(
- WebFloatPoint(20, 220)); // An A-link with cross-hair cursor.
+ gfx::PointF(20, 220)); // An A-link with cross-hair cursor.
web_view_impl->EnableTapHighlightAtPoint(GetTargetedEvent(touch_event));
EXPECT_FALSE(GetLinkHighlightImpl());
- touch_event.SetPositionInWidget(WebFloatPoint(20, 260)); // A text input box.
+ touch_event.SetPositionInWidget(gfx::PointF(20, 260)); // A text input box.
web_view_impl->EnableTapHighlightAtPoint(GetTargetedEvent(touch_event));
EXPECT_FALSE(GetLinkHighlightImpl());
}
@@ -188,7 +187,7 @@ TEST_P(LinkHighlightImplTest, resetDuringNodeRemoval) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests(),
WebGestureDevice::kTouchscreen);
- touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 20));
GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
Node* touch_node = web_view_impl->BestTapNode(targeted_event);
@@ -197,14 +196,14 @@ TEST_P(LinkHighlightImplTest, resetDuringNodeRemoval) {
web_view_impl->EnableTapHighlightAtPoint(targeted_event);
const auto* highlight = GetLinkHighlightImpl();
ASSERT_TRUE(highlight);
- EXPECT_EQ(touch_node, highlight->GetNode());
+ EXPECT_EQ(touch_node->GetLayoutObject(), highlight->GetLayoutObject());
touch_node->remove(IGNORE_EXCEPTION_FOR_TESTING);
UpdateAllLifecyclePhases();
ASSERT_EQ(highlight, GetLinkHighlightImpl());
ASSERT_TRUE(highlight);
- EXPECT_FALSE(highlight->GetNode());
+ EXPECT_FALSE(highlight->GetLayoutObject());
}
// A lifetime test: delete LayerTreeView while running LinkHighlights.
@@ -220,7 +219,7 @@ TEST_P(LinkHighlightImplTest, resetLayerTreeView) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests(),
WebGestureDevice::kTouchscreen);
- touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 20));
GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
Node* touch_node = web_view_impl->BestTapNode(targeted_event);
@@ -245,7 +244,7 @@ TEST_P(LinkHighlightImplTest, HighlightLayerEffectNode) {
WebInputEvent::kNoModifiers,
WebInputEvent::GetStaticTimeStampForTests(),
WebGestureDevice::kTouchscreen);
- touch_event.SetPositionInWidget(WebFloatPoint(20, 20));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 20));
GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
Node* touch_node = web_view_impl->BestTapNode(targeted_event);
@@ -309,7 +308,7 @@ TEST_P(LinkHighlightImplTest, MultiColumn) {
WebInputEvent::GetStaticTimeStampForTests(),
WebGestureDevice::kTouchscreen);
// This will touch the link under multicol.
- touch_event.SetPositionInWidget(WebFloatPoint(20, 300));
+ touch_event.SetPositionInWidget(gfx::PointF(20, 300));
GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
Node* touch_node = web_view_impl->BestTapNode(targeted_event);
@@ -380,4 +379,28 @@ TEST_P(LinkHighlightImplTest, MultiColumn) {
EXPECT_EQ(layer_count_before_highlight, LayerCount());
}
+TEST_P(LinkHighlightImplTest, DisplayContents) {
+ WebViewImpl* web_view_impl = web_view_helper_.GetWebView();
+
+ int page_width = 640;
+ int page_height = 480;
+ web_view_impl->MainFrameWidget()->Resize(WebSize(page_width, page_height));
+ UpdateAllLifecyclePhases();
+
+ WebGestureEvent touch_event(WebInputEvent::kGestureShowPress,
+ WebInputEvent::kNoModifiers,
+ WebInputEvent::GetStaticTimeStampForTests(),
+ WebGestureDevice::kTouchscreen);
+ // This will touch the div with display:contents and cursor:pointer.
+ touch_event.SetPositionInWidget(gfx::PointF(20, 400));
+
+ GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event);
+ const Node* touched_node = targeted_event.GetHitTestResult().InnerNode();
+ EXPECT_TRUE(touched_node->IsTextNode());
+ EXPECT_FALSE(web_view_impl->BestTapNode(targeted_event));
+
+ web_view_impl->EnableTapHighlightAtPoint(targeted_event);
+ EXPECT_FALSE(GetLinkHighlightImpl());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc b/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc
index 3d0509ef618..129ae0e73ca 100644
--- a/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/list_marker_painter.cc
@@ -25,6 +25,8 @@ void ListMarkerPainter::PaintSymbol(const PaintInfo& paint_info,
const IntRect& marker) {
DCHECK(object);
GraphicsContext& context = paint_info.context;
+ ScopedDarkModeElementRoleOverride list_symbol(
+ &context, DarkModeFilter::ElementRole::kListSymbol);
Color color(object->ResolveColor(GetCSSPropertyColor()));
if (BoxModelObjectPainter::ShouldForceWhiteBackgroundForPrintEconomy(
object->GetDocument(), style))
@@ -108,8 +110,7 @@ void ListMarkerPainter::Paint(const PaintInfo& paint_info) {
Color color(layout_list_marker_.ResolveColor(GetCSSPropertyColor()));
if (BoxModelObjectPainter::ShouldForceWhiteBackgroundForPrintEconomy(
- layout_list_marker_.ListItem()->GetDocument(),
- layout_list_marker_.StyleRef()))
+ layout_list_marker_.GetDocument(), layout_list_marker_.StyleRef()))
color = TextPainter::TextColorForWhiteBackground(color);
// Apply the color to the list marker text.
diff --git a/chromium/third_party/blink/renderer/core/paint/multi_column_set_painter.cc b/chromium/third_party/blink/renderer/core/paint/multi_column_set_painter.cc
index c9a4348d6f1..f16be7a8e54 100644
--- a/chromium/third_party/blink/renderer/core/paint/multi_column_set_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/multi_column_set_painter.cc
@@ -29,7 +29,7 @@ void MultiColumnSetPainter::PaintObject(const PaintInfo& paint_info,
// It's also really unlikely that the columns would overlap another block.
if (!layout_multi_column_set_.FlowThread() ||
(paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelection))
+ paint_info.phase != PaintPhase::kSelectionDragImage))
return;
PaintColumnRules(paint_info, paint_offset);
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/README.md b/chromium/third_party/blink/renderer/core/paint/ng/README.md
index 70c1fb9bb76..31778f46d11 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/README.md
+++ b/chromium/third_party/blink/renderer/core/paint/ng/README.md
@@ -59,6 +59,25 @@ even though the inline block LayoutObject has children.
If the inline block has another inline block which LayoutNG can handle,
another NGPaintFragment tree is created for the inner inline block.
+### NGPhysicalFragment traversal ###
+
+When possible (when sufficiently transitioned to LayoutNG), we'll paint and
+hit-test by traversing the physical fragment tree, rather than traversing the
+LayoutObject tree. This is important for block fragmentation, where a CSS layout
+box (LayoutObject) may be split into multiple fragments, and it's the
+relationship between the fragments (not the layout objects) that determines the
+offsets. In LayoutNG, there are also fragments that have no corresponding layout
+object - e.g. a column (or other types of [fragmentainer]s too).
+
+Traditionally, when doing block fragmentation (multicol) in legacy layout, we
+have to perform some complicated calculations, where we map and slice layout
+objects into fragments during pre-paint. In LayoutNG this job is now as a
+natural part of layout. So, all we have to do for painting and hit-testing, is
+traverse the fragments. A fragment holds a list of child fragments and their
+offsets. The offsets are relative to the parent fragment. As such, it's a rather
+straight-forward job for pre-paint to calculate the offsets and bounding box.
+
[LayoutNG]: ../../layout/ng/README.md
[NGPaintFragment]: ng_paint_fragment.h
[NGPhysicalFragment]: ../../layout/ng/ng_physical_fragment.h
+[fragmentainer]: https://drafts.csswg.org/css-break/#fragmentation-container
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index 6260eae3666..e8ff0f43f2f 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
+#include "base/containers/adapters.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -28,6 +29,7 @@
#include "third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
@@ -44,8 +46,6 @@
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h"
namespace blink {
@@ -103,7 +103,7 @@ bool HitTestCulledInlineAncestors(HitTestResult& result,
// To be passed as |accumulated_offset| to LayoutInline::HitTestCulledInline,
// where it equals the physical offset of the containing block in paint layer.
const PhysicalOffset fallback_accumulated_offset =
- physical_offset - fragment.InlineOffsetToContainerBox();
+ physical_offset - fragment.OffsetInContainerBlock();
const LayoutObject* limit_layout_object =
parent.PhysicalFragment().IsLineBox() ? parent.Parent()->GetLayoutObject()
: parent.GetLayoutObject();
@@ -156,71 +156,122 @@ bool FragmentRequiresLegacyFallback(const NGPhysicalFragment& fragment) {
// Fallback to LayoutObject if this is a root of NG block layout.
// If this box is for this painter, LayoutNGBlockFlow will call this back.
// Otherwise it calls legacy painters.
- return fragment.IsBlockFormattingContextRoot();
+ return fragment.IsFormattingContextRoot();
}
-// Recursively build up backplates behind inline text boxes, each split at the
-// paragraph level. Store the results in paragraph_backplates.
-void BuildBackplate(const NGPaintFragment* line,
- const PhysicalOffset& paint_offset,
- PhysicalRect* current_backplate,
- int* consecutive_line_breaks,
- Vector<PhysicalRect>* paragraph_backplates) {
- DCHECK(current_backplate && consecutive_line_breaks && paragraph_backplates);
-
+// Returns a vector of backplates that surround the paragraphs of text within
+// line_boxes.
+//
+// This function traverses descendants of an inline formatting context in
+// pre-order DFS and build up backplates behind inline text boxes, each split at
+// the paragraph level. Store the results in paragraph_backplates.
+Vector<PhysicalRect> BuildBackplate(NGInlineCursor* descendants,
+ const PhysicalOffset& paint_offset) {
// The number of consecutive forced breaks that split the backplate by
// paragraph.
static constexpr int kMaxConsecutiveLineBreaks = 2;
+ struct Backplates {
+ STACK_ALLOCATED();
+
+ public:
+ void AddTextRect(const PhysicalRect& box_rect) {
+ if (consecutive_line_breaks >= kMaxConsecutiveLineBreaks) {
+ // This is a paragraph point.
+ paragraph_backplates.push_back(current_backplate);
+ current_backplate = PhysicalRect();
+ }
+ consecutive_line_breaks = 0;
+
+ current_backplate.Unite(box_rect);
+ }
+
+ void AddLineBreak() { consecutive_line_breaks++; }
+
+ Vector<PhysicalRect> paragraph_backplates;
+ PhysicalRect current_backplate;
+ int consecutive_line_breaks = 0;
+ } backplates;
+
// Build up and paint backplates of all child inline text boxes. We are not
// able to simply use the linebox rect to compute the backplate because the
// backplate should only be painted for inline text and not for atomic
// inlines.
- for (const NGPaintFragment* child : line->Children()) {
- const NGPhysicalFragment& child_fragment = child->PhysicalFragment();
- if (child_fragment.IsHiddenForPaint() || child_fragment.IsFloating())
- continue;
- if (auto* text_fragment =
- DynamicTo<NGPhysicalTextFragment>(child_fragment)) {
- if (text_fragment->IsLineBreak()) {
- (*consecutive_line_breaks)++;
+ for (; *descendants; descendants->MoveToNext()) {
+ if (const NGPaintFragment* child = descendants->CurrentPaintFragment()) {
+ const NGPhysicalFragment& child_fragment = child->PhysicalFragment();
+ if (child_fragment.IsHiddenForPaint() || child_fragment.IsFloating())
continue;
- }
+ if (auto* text_fragment =
+ DynamicTo<NGPhysicalTextFragment>(child_fragment)) {
+ if (text_fragment->IsLineBreak()) {
+ backplates.AddLineBreak();
+ continue;
+ }
- if (*consecutive_line_breaks >= kMaxConsecutiveLineBreaks) {
- // This is a paragraph point.
- paragraph_backplates->push_back(*current_backplate);
- *current_backplate = PhysicalRect();
+ PhysicalRect box_rect(child->OffsetInContainerBlock() + paint_offset,
+ child->Size());
+ backplates.AddTextRect(box_rect);
}
- *consecutive_line_breaks = 0;
- PhysicalRect box_rect(child->InlineOffsetToContainerBox() + paint_offset,
- child->Size());
- current_backplate->Unite(box_rect);
+ continue;
}
- if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) {
- // If a fragment box was reached, continue to recursively build
- // up the backplate.
- BuildBackplate(child, paint_offset, current_backplate,
- consecutive_line_breaks, paragraph_backplates);
+ if (const NGFragmentItem* child_item = descendants->CurrentItem()) {
+ if (child_item->IsHiddenForPaint())
+ continue;
+ if (child_item->IsText()) {
+ if (child_item->IsLineBreak()) {
+ backplates.AddLineBreak();
+ continue;
+ }
+
+ PhysicalRect box_rect(
+ child_item->OffsetInContainerBlock() + paint_offset,
+ child_item->Size());
+ backplates.AddTextRect(box_rect);
+ }
+ continue;
}
+ NOTREACHED();
}
+
+ if (!backplates.current_backplate.IsEmpty())
+ backplates.paragraph_backplates.push_back(backplates.current_backplate);
+ return backplates.paragraph_backplates;
}
-// Returns a vector of backplates that surround the paragraphs of text within
-// line_boxes.
-Vector<PhysicalRect> BuildBackplate(const NGPaintFragment::ChildList line_boxes,
- const PhysicalOffset& paint_offset) {
- Vector<PhysicalRect> paragraph_backplates;
- PhysicalRect current_backplate;
- int consecutive_line_breaks = 0;
- for (const NGPaintFragment* line : line_boxes) {
- // Recursively build up and paint backplates for line boxes containing text.
- BuildBackplate(line, paint_offset, &current_backplate,
- &consecutive_line_breaks, &paragraph_backplates);
+bool HitTestAllPhasesInFragment(const NGPhysicalBoxFragment& fragment,
+ const HitTestLocation& hit_test_location,
+ PhysicalOffset accumulated_offset,
+ HitTestResult* result) {
+ // Hit test all phases of inline blocks, inline tables, replaced elements and
+ // non-positioned floats as if they created their own (pseudo- [1]) stacking
+ // context. https://www.w3.org/TR/CSS22/zindex.html#painting-order
+ //
+ // [1] As if it creates a new stacking context, but any positioned descendants
+ // and descendants which actually create a new stacking context should be
+ // considered part of the parent stacking context, not this new one.
+
+ if (!fragment.CanTraverse()) {
+ return fragment.GetMutableLayoutObject()->HitTestAllPhases(
+ *result, hit_test_location, accumulated_offset);
}
- if (!current_backplate.IsEmpty())
- paragraph_backplates.push_back(current_backplate);
- return paragraph_backplates;
+
+ return NGBoxFragmentPainter(To<NGPhysicalBoxFragment>(fragment))
+ .HitTestAllPhases(*result, hit_test_location, accumulated_offset);
+}
+
+bool NodeAtPointInFragment(const NGPhysicalBoxFragment& fragment,
+ const HitTestLocation& hit_test_location,
+ PhysicalOffset accumulated_offset,
+ HitTestAction action,
+ HitTestResult* result) {
+ if (!fragment.CanTraverse()) {
+ return fragment.GetMutableLayoutObject()->NodeAtPoint(
+ *result, hit_test_location, accumulated_offset, action);
+ }
+
+ return NGBoxFragmentPainter(fragment).NodeAtPoint(*result, hit_test_location,
+ accumulated_offset, action);
}
} // anonymous namespace
@@ -234,16 +285,35 @@ const NGBorderEdges& NGBoxFragmentPainter::BorderEdges() const {
return *border_edges_;
}
+PhysicalRect NGBoxFragmentPainter::SelfInkOverflow() const {
+ if (paint_fragment_)
+ return paint_fragment_->SelfInkOverflow();
+ if (box_item_)
+ return box_item_->SelfInkOverflow();
+ const NGPhysicalFragment& fragment = PhysicalFragment();
+ DCHECK(fragment.IsBox() && !fragment.IsInlineBox());
+ return ToLayoutBox(fragment.GetLayoutObject())
+ ->PhysicalSelfVisualOverflowRect();
+}
+
+PhysicalRect NGBoxFragmentPainter::ContentsInkOverflow() const {
+ if (const LayoutObject* layout_object = box_fragment_.GetLayoutObject())
+ return ToLayoutBox(layout_object)->PhysicalContentsVisualOverflowRect();
+ return box_fragment_.ContentsInkOverflow();
+}
+
void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) {
- if (PhysicalFragment().IsAtomicInline() &&
+ if (PhysicalFragment().IsPaintedAtomically() &&
!box_fragment_.HasSelfPaintingLayer())
- PaintAtomicInline(paint_info);
+ PaintAllPhasesAtomically(paint_info);
else
PaintInternal(paint_info);
}
void NGBoxFragmentPainter::PaintInternal(const PaintInfo& paint_info) {
- ScopedPaintState paint_state(box_fragment_, paint_info);
+ // Avoid initialization of Optional ScopedPaintState::chunk_properties_
+ // and ScopedPaintState::adjusted_paint_info_.
+ STACK_UNINITIALIZED ScopedPaintState paint_state(box_fragment_, paint_info);
if (!ShouldPaint(paint_state))
return;
@@ -251,6 +321,15 @@ void NGBoxFragmentPainter::PaintInternal(const PaintInfo& paint_info) {
PhysicalOffset paint_offset = paint_state.PaintOffset();
PaintPhase original_phase = info.phase;
+ ScopedPaintTimingDetectorBlockPaintHook
+ scoped_paint_timing_detector_block_paint_hook;
+ if (original_phase == PaintPhase::kForeground &&
+ box_fragment_.GetLayoutObject()->IsBox()) {
+ scoped_paint_timing_detector_block_paint_hook.EmplaceIfNeeded(
+ ToLayoutBox(*box_fragment_.GetLayoutObject()),
+ paint_info.context.GetPaintController().CurrentPaintChunkProperties());
+ }
+
if (original_phase == PaintPhase::kOutline) {
info.phase = PaintPhase::kDescendantOutlinesOnly;
} else if (ShouldPaintSelfBlockBackground(original_phase)) {
@@ -318,17 +397,18 @@ void NGBoxFragmentPainter::RecordScrollHitTestData(
.RecordScrollHitTestData(paint_info, background_client);
}
-void NGBoxFragmentPainter::RecordHitTestDataForLine(
- const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset,
- const NGPhysicalFragment& line,
- const DisplayItemClient& display_item_client) {
- PhysicalRect border_box = line.LocalRect();
- border_box.offset += paint_offset;
- HitTestDisplayItem::Record(
- paint_info.context, display_item_client,
- HitTestRect(border_box.ToLayoutRect(),
- PhysicalFragment().EffectiveAllowedTouchAction()));
+bool NGBoxFragmentPainter::ShouldRecordHitTestData(
+ const PaintInfo& paint_info) {
+ // Hit test data are only needed for compositing. This flag is used for for
+ // printing and drag images which do not need hit testing.
+ if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
+ return false;
+
+ // If an object is not visible, it does not participate in hit testing.
+ if (PhysicalFragment().Style().Visibility() != EVisibility::kVisible)
+ return false;
+
+ return true;
}
void NGBoxFragmentPainter::PaintObject(
@@ -355,39 +435,46 @@ void NGBoxFragmentPainter::PaintObject(
return;
}
- if (paint_phase == PaintPhase::kForeground &&
- paint_info.ShouldAddUrlMetadata()) {
- NGFragmentPainter(box_fragment_, paint_fragment_)
- .AddURLRectIfNeeded(paint_info, paint_offset);
+ if (paint_phase == PaintPhase::kForeground) {
+ if (paint_info.ShouldAddUrlMetadata()) {
+ NGFragmentPainter(box_fragment_, GetDisplayItemClient())
+ .AddURLRectIfNeeded(paint_info, paint_offset);
+ }
+ if (is_visible && box_fragment_.IsMathMLFraction())
+ NGMathMLPainter(box_fragment_).PaintFractionBar(paint_info, paint_offset);
}
if (paint_phase != PaintPhase::kSelfOutlineOnly &&
(!physical_box_fragment.Children().empty() ||
- physical_box_fragment.HasItems() || descendants_) &&
+ physical_box_fragment.HasItems() || inline_box_cursor_) &&
!paint_info.DescendantPaintingBlocked()) {
- if (RuntimeEnabledFeatures::LayoutNGFragmentPaintEnabled()) {
- if (UNLIKELY(paint_phase == PaintPhase::kForeground &&
- box_fragment_.Style().HasColumnRule()))
- PaintColumnRules(paint_info, paint_offset);
- }
+ if (UNLIKELY(paint_phase == PaintPhase::kForeground &&
+ box_fragment_.Style().HasColumnRule()))
+ PaintColumnRules(paint_info, paint_offset);
if (paint_phase != PaintPhase::kFloat) {
- if (UNLIKELY(descendants_)) {
+ if (UNLIKELY(inline_box_cursor_)) {
// Use the descendants cursor for this painter if it is given.
// Self-painting inline box paints only parts of the container block.
// Adjust |paint_offset| because it is the offset of the inline box, but
// |descendants_| has offsets to the contaiing block.
- DCHECK(box_item_ && box_item_->HasSelfPaintingLayer());
+ DCHECK(box_item_);
+ NGInlineCursor descendants = inline_box_cursor_->CursorForDescendants();
const PhysicalOffset paint_offset_to_inline_formatting_context =
- paint_offset - box_item_->Offset();
+ paint_offset - box_item_->OffsetInContainerBlock();
PaintInlineItems(paint_info.ForDescendants(),
paint_offset_to_inline_formatting_context,
- descendants_);
+ box_item_->OffsetInContainerBlock(), &descendants);
} else if (items_) {
- // Paint |NGFragmentItems| for this block if we have one.
- NGInlineCursor cursor(*items_);
- PaintInlineItems(paint_info.ForDescendants(), paint_offset, &cursor);
- } else if (physical_box_fragment.ChildrenInline()) {
+ if (physical_box_fragment.IsBlockFlow()) {
+ PaintBlockFlowContents(paint_info, paint_offset);
+ } else {
+ DCHECK(physical_box_fragment.IsInlineBox());
+ NGInlineCursor cursor(*items_);
+ PaintInlineItems(paint_info.ForDescendants(), paint_offset,
+ PhysicalOffset(), &cursor);
+ }
+ } else if (physical_box_fragment.IsInlineFormattingContext()) {
DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK(paint_fragment_);
if (physical_box_fragment.IsBlockFlow()) {
@@ -403,12 +490,12 @@ void NGBoxFragmentPainter::PaintObject(
paint_offset);
}
} else {
- PaintBlockChildren(paint_info);
+ PaintBlockChildren(paint_info, paint_offset);
}
}
if (paint_phase == PaintPhase::kFloat ||
- paint_phase == PaintPhase::kSelection ||
+ paint_phase == PaintPhase::kSelectionDragImage ||
paint_phase == PaintPhase::kTextClip) {
if (physical_box_fragment.HasFloatingDescendantsForPaint())
PaintFloats(paint_info);
@@ -416,7 +503,7 @@ void NGBoxFragmentPainter::PaintObject(
}
if (ShouldPaintSelfOutline(paint_phase)) {
- NGFragmentPainter(box_fragment_, paint_fragment_)
+ NGFragmentPainter(box_fragment_, GetDisplayItemClient())
.PaintOutline(paint_info, paint_offset);
}
@@ -445,18 +532,20 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
const PhysicalOffset& paint_offset) {
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
const LayoutObject* layout_object = fragment.GetLayoutObject();
-
- DCHECK(fragment.ChildrenInline());
- DCHECK(paint_fragment_);
+ DCHECK(fragment.IsInlineFormattingContext());
// When the layout-tree gets into a bad state, we can end up trying to paint
// a fragment with inline children, without a paint fragment. See:
// http://crbug.com/1022545
- if (!paint_fragment_) {
+ if ((!paint_fragment_ && !items_) ||
+ (layout_object && layout_object->NeedsLayout())) {
NOTREACHED();
return;
}
+ // Trying to rule out a null GraphicsContext, see: https://crbug.com/1040298
+ CHECK(&paint_info.context);
+
// Check if there were contents to be painted and return early if none.
// The union of |ContentsInkOverflow()| and |LocalRect()| covers the rect to
// check, in both cases of:
@@ -467,37 +556,73 @@ void NGBoxFragmentPainter::PaintBlockFlowContents(
// |LayoutOverflow()|, but this can be approximiated with
// |ContentsInkOverflow()|.
PhysicalRect content_ink_rect = fragment.LocalRect();
- content_ink_rect.Unite(paint_fragment_->ContentsInkOverflow());
+ content_ink_rect.Unite(ContentsInkOverflow());
content_ink_rect.offset += PhysicalOffset(paint_offset);
if (!paint_info.GetCullRect().Intersects(content_ink_rect.ToLayoutRect()))
return;
- DCHECK(layout_object->IsLayoutBlockFlow());
- const auto& layout_block = To<LayoutBlock>(*layout_object);
- DCHECK(layout_block.ChildrenInline());
- PaintLineBoxChildren(paint_fragment_->Children(), paint_info.ForDescendants(),
- paint_offset);
+ if (paint_fragment_) {
+ NGInlineCursor children(*paint_fragment_);
+ PaintLineBoxChildren(&children, paint_info.ForDescendants(), paint_offset);
+ return;
+ }
+ DCHECK(items_);
+ NGInlineCursor children(*items_);
+ PaintLineBoxChildren(&children, paint_info.ForDescendants(), paint_offset);
}
-void NGBoxFragmentPainter::PaintBlockChildren(const PaintInfo& paint_info) {
- DCHECK(!box_fragment_.ChildrenInline());
- DCHECK(!box_fragment_.GetLayoutObject()->ChildrenInline());
+void NGBoxFragmentPainter::PaintBlockChildren(const PaintInfo& paint_info,
+ PhysicalOffset paint_offset) {
+ DCHECK(!box_fragment_.IsInlineFormattingContext());
PaintInfo paint_info_for_descendants = paint_info.ForDescendants();
for (const NGLink& child : box_fragment_.Children()) {
const NGPhysicalFragment& child_fragment = *child;
+ DCHECK(child_fragment.IsBox());
if (child_fragment.HasSelfPaintingLayer() || child_fragment.IsFloating() ||
child_fragment.IsColumnBox())
continue;
- if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) {
- // TODO(kojii): We could skip going through |LayoutObject| when we know
- // children are always laid out by NG. See
- // |FragmentRequiresLegacyFallback|.
- child_fragment.GetLayoutObject()->Paint(paint_info_for_descendants);
- } else {
- DCHECK_EQ(child_fragment.Type(),
- NGPhysicalFragment::kFragmentRenderedLegend);
+ const auto& box_child_fragment = To<NGPhysicalBoxFragment>(child_fragment);
+ if (box_child_fragment.CanTraverse()) {
+ if (!box_child_fragment.GetLayoutObject()) {
+ // It's normally FragmentData that provides us with the paint offset.
+ // FragmentData is (at least currently) associated with a LayoutObject.
+ // If we have no LayoutObject, we have no FragmentData, so we need to
+ // calculate the offset on our own (which is very simple, anyway).
+ // Bypass Paint() and jump directly to PaintObject(), to skip the code
+ // that assumes that we have a LayoutObject (and FragmentData).
+ PhysicalOffset child_offset = paint_offset + child.offset;
+ NGBoxFragmentPainter(box_child_fragment)
+ .PaintObject(paint_info, child_offset);
+ continue;
+ }
+
+ NGBoxFragmentPainter(box_child_fragment)
+ .Paint(paint_info_for_descendants);
+ continue;
}
+ child_fragment.GetLayoutObject()->Paint(paint_info_for_descendants);
+ }
+}
+
+void NGBoxFragmentPainter::PaintFloatingItems(const PaintInfo& paint_info,
+ NGInlineCursor* cursor) {
+ for (; *cursor; cursor->MoveToNext()) {
+ const NGFragmentItem* item = cursor->Current().Item();
+ DCHECK(item);
+ const NGPhysicalBoxFragment* child_fragment = item->BoxFragment();
+ if (!child_fragment || child_fragment->HasSelfPaintingLayer() ||
+ !child_fragment->IsFloating())
+ continue;
+ // TODO(kojii): The float is outside of the inline formatting context and
+ // that it maybe another NG inline formatting context, NG block layout, or
+ // legacy. NGBoxFragmentPainter can handle only the first case. In order
+ // to cover more tests for other two cases, we always fallback to legacy,
+ // which will forward back to NGBoxFragmentPainter if the float is for
+ // NGBoxFragmentPainter. We can shortcut this for the first case when
+ // we're more stable.
+ ObjectPainter(*child_fragment->GetLayoutObject())
+ .PaintAllPhasesAtomically(paint_info);
}
}
@@ -505,60 +630,93 @@ void NGBoxFragmentPainter::PaintFloatingChildren(
const NGPhysicalContainerFragment& container,
const PaintInfo& paint_info,
const PaintInfo& float_paint_info) {
-#if DCHECK_IS_ON()
- // Floats are in the fragment tree, not in the fragment item list.
- if (const NGPhysicalBoxFragment* box_fragment =
+ DCHECK(container.HasFloatingDescendantsForPaint());
+
+ if (const NGPhysicalBoxFragment* box =
DynamicTo<NGPhysicalBoxFragment>(&container)) {
- if (const NGFragmentItems* items = box_fragment->Items()) {
- DCHECK(std::none_of(
- items->Items().begin(), items->Items().end(), [](const auto& item) {
- return item->BoxFragment() && item->BoxFragment()->IsFloating();
- }));
+ if (const NGFragmentItems* items = box->Items()) {
+ NGInlineCursor cursor(*items);
+ PaintFloatingItems(float_paint_info, &cursor);
+ return;
+ }
+ if (inline_box_cursor_) {
+ DCHECK(box->IsInlineBox());
+ NGInlineCursor descendants = inline_box_cursor_->CursorForDescendants();
+ PaintFloatingItems(float_paint_info, &descendants);
+ return;
}
+ DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() ||
+ !box->IsInlineBox());
}
-#endif
for (const NGLink& child : container.Children()) {
const NGPhysicalFragment& child_fragment = *child;
if (child_fragment.HasSelfPaintingLayer() || child_fragment.IsColumnBox())
continue;
- // Atomic-inlines paint atomically, and shouldn't be traversed.
- // TODO(layout-dev): This check should include all children which paint
- // atomically.
- if (child_fragment.IsAtomicInline())
+ if (child_fragment.CanTraverse()) {
+ if (child_fragment.IsFloating()) {
+ NGBoxFragmentPainter(To<NGPhysicalBoxFragment>(child_fragment))
+ .Paint(float_paint_info);
+ continue;
+ }
+
+ // Any non-floated children which paint atomically shouldn't be traversed.
+ if (child_fragment.IsPaintedAtomically())
+ continue;
+ } else {
+ if (child_fragment.IsFloating()) {
+ // TODO(kojii): The float is outside of the inline formatting context
+ // and that it maybe another NG inline formatting context, NG block
+ // layout, or legacy. NGBoxFragmentPainter can handle only the first
+ // case. In order to cover more tests for other two cases, we always
+ // fallback to legacy, which will forward back to NGBoxFragmentPainter
+ // if the float is for NGBoxFragmentPainter. We can shortcut this for
+ // the first case when we're more stable.
+
+ ObjectPainter(*child_fragment.GetLayoutObject())
+ .PaintAllPhasesAtomically(float_paint_info);
+ continue;
+ }
+
+ // Any children which paint atomically shouldn't be traversed.
+ if (child_fragment.IsPaintedAtomically())
+ continue;
+
+ if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox &&
+ FragmentRequiresLegacyFallback(child_fragment)) {
+ child_fragment.GetLayoutObject()->Paint(paint_info);
+ continue;
+ }
+ }
+
+ // The selection paint traversal is special. We will visit all fragments
+ // (including floats) in the normal paint traversal. There isn't any point
+ // performing the special float traversal here.
+ if (paint_info.phase == PaintPhase::kSelectionDragImage)
continue;
- if (child_fragment.IsFloating()) {
- // TODO(kojii): The float is outside of the inline formatting context and
- // that it maybe another NG inline formatting context, NG block layout, or
- // legacy. NGBoxFragmentPainter can handle only the first case. In order
- // to cover more tests for other two cases, we always fallback to legacy,
- // which will forward back to NGBoxFragmentPainter if the float is for
- // NGBoxFragmentPainter. We can shortcut this for the first case when
- // we're more stable.
- ObjectPainter(*child_fragment.GetLayoutObject())
- .PaintAllPhasesAtomically(float_paint_info);
+ const auto* child_container =
+ DynamicTo<NGPhysicalContainerFragment>(&child_fragment);
+ if (!child_container || !child_container->HasFloatingDescendantsForPaint())
continue;
- }
- if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox &&
- FragmentRequiresLegacyFallback(child_fragment)) {
- child_fragment.GetLayoutObject()->Paint(paint_info);
+ if (child_container->HasOverflowClip()) {
+ // We need to properly visit this fragment for painting, rather than
+ // jumping directly to its children (which is what we normally do when
+ // looking for floats), in order to set up the clip rectangle.
+ NGBoxFragmentPainter(To<NGPhysicalBoxFragment>(*child_container))
+ .Paint(paint_info);
continue;
}
- if (const auto* child_container =
- DynamicTo<NGPhysicalContainerFragment>(&child_fragment)) {
- if (child_container->HasFloatingDescendantsForPaint())
- PaintFloatingChildren(*child_container, paint_info, float_paint_info);
- }
+ PaintFloatingChildren(*child_container, paint_info, float_paint_info);
}
}
void NGBoxFragmentPainter::PaintFloats(const PaintInfo& paint_info) {
DCHECK(PhysicalFragment().HasFloatingDescendantsForPaint() ||
- !PhysicalFragment().ChildrenInline());
+ !PhysicalFragment().IsInlineFormattingContext());
PaintInfo float_paint_info(paint_info);
if (paint_info.phase == PaintPhase::kFloat)
@@ -645,12 +803,10 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackground(
}
}
- if (NGFragmentPainter::ShouldRecordHitTestData(paint_info,
- PhysicalFragment())) {
- HitTestDisplayItem::Record(
- paint_info.context, *background_client,
- HitTestRect(paint_rect.ToLayoutRect(),
- PhysicalFragment().EffectiveAllowedTouchAction()));
+ if (ShouldRecordHitTestData(paint_info)) {
+ paint_info.context.GetPaintController().RecordHitTestData(
+ *background_client, PixelSnappedIntRect(paint_rect),
+ PhysicalFragment().EffectiveAllowedTouchAction());
}
bool needs_scroll_hit_test = true;
@@ -677,24 +833,6 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackground(
// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
// eliminate LayoutObject dependency were done yet.
-bool NGBoxFragmentPainter::BackgroundIsKnownToBeOpaque(
- const PaintInfo& paint_info) {
- const LayoutBox& layout_box = ToLayoutBox(*box_fragment_.GetLayoutObject());
-
- // If the box has multiple fragments, its VisualRect is the bounding box of
- // all fragments' visual rects, which is likely to cover areas that are not
- // covered by painted background.
- if (layout_box.FirstFragment().NextFragment())
- return false;
-
- PhysicalRect bounds = IsPaintingScrollingBackground(paint_info)
- ? layout_box.PhysicalLayoutOverflowRect()
- : layout_box.PhysicalSelfVisualOverflowRect();
- return layout_box.BackgroundIsKnownToBeOpaqueInRect(bounds);
-}
-
-// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
-// eliminate LayoutObject dependency were done yet.
void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
const PaintInfo& paint_info,
const PhysicalRect& paint_rect,
@@ -705,17 +843,9 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
const ComputedStyle& style = box_fragment_.Style();
base::Optional<DisplayItemCacheSkipper> cache_skipper;
- // Disable cache in under-invalidation checking mode for MediaSliderPart
- // because we always paint using the latest data (buffered ranges, current
- // time and duration) which may be different from the cached data, and for
- // delayed-invalidation object because it may change before it's actually
- // invalidated. Note that we still report harmless under-invalidation of
- // non-delayed-invalidation animated background, which should be ignored.
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
- (style.EffectiveAppearance() == kMediaSliderPart ||
- layout_box.ShouldDelayFullPaintInvalidation())) {
+ ShouldSkipPaintUnderInvalidationChecking(layout_box))
cache_skipper.emplace(paint_info.context);
- }
BoxDecorationData box_decoration_data(paint_info, PhysicalFragment());
if (!box_decoration_data.ShouldPaint())
@@ -730,11 +860,6 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
DisplayItem::kBoxDecorationBackground);
GraphicsContextStateSaver state_saver(paint_info.context, false);
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- paint_rect.EdgesOnPixelBoundaries() &&
- BackgroundIsKnownToBeOpaque(paint_info))
- recorder.SetKnownToBeOpaque();
-
const NGBorderEdges& border_edges = BorderEdges();
if (box_decoration_data.ShouldPaintShadow()) {
PaintNormalBoxShadow(paint_info, paint_rect, style, border_edges.line_left,
@@ -971,14 +1096,15 @@ void NGBoxFragmentPainter::PaintInlineChildBoxUsingLegacyFallback(
void NGBoxFragmentPainter::PaintAllPhasesAtomically(
const PaintInfo& paint_info) {
// Self-painting AtomicInlines should go to normal paint logic.
- DCHECK(!(PhysicalFragment().IsAtomicInline() &&
+ DCHECK(!(PhysicalFragment().IsPaintedAtomically() &&
box_fragment_.HasSelfPaintingLayer()));
// Pass PaintPhaseSelection and PaintPhaseTextClip is handled by the regular
// foreground paint implementation. We don't need complete painting for these
// phases.
PaintPhase phase = paint_info.phase;
- if (phase == PaintPhase::kSelection || phase == PaintPhase::kTextClip)
+ if (phase == PaintPhase::kSelectionDragImage ||
+ phase == PaintPhase::kTextClip)
return PaintInternal(paint_info);
if (phase != PaintPhase::kForeground)
@@ -1003,39 +1129,33 @@ void NGBoxFragmentPainter::PaintAllPhasesAtomically(
void NGBoxFragmentPainter::PaintInlineItems(const PaintInfo& paint_info,
const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset,
NGInlineCursor* cursor) {
- ScopedPaintTimingDetectorBlockPaintHook
- scoped_paint_timing_detector_block_paint_hook;
- // TODO(kojii): Copy more from |PaintLineBoxChildren|.
-
while (*cursor) {
const NGFragmentItem* item = cursor->CurrentItem();
DCHECK(item);
switch (item->Type()) {
case NGFragmentItem::kText:
case NGFragmentItem::kGeneratedText:
- PaintTextItem(*cursor, paint_info, paint_offset);
- break;
- case NGFragmentItem::kLine:
- if (PaintLineBoxItem(*item, paint_info, paint_offset) ==
- kSkipChildren) {
- cursor->MoveToNextSkippingChildren();
- continue;
- }
+ if (!item->IsHiddenForPaint())
+ PaintTextItem(*cursor, paint_info, paint_offset, parent_offset);
+ cursor->MoveToNext();
break;
case NGFragmentItem::kBox:
- if (PaintBoxItem(*item, paint_info, paint_offset) == kSkipChildren) {
- cursor->MoveToNextSkippingChildren();
- continue;
- }
+ if (!item->IsHiddenForPaint())
+ PaintBoxItem(*item, *cursor, paint_info, paint_offset, parent_offset);
+ cursor->MoveToNextSkippingChildren();
+ break;
+ case NGFragmentItem::kLine:
+ NOTREACHED();
+ cursor->MoveToNext();
break;
}
- cursor->MoveToNext();
}
}
-// Paint a line box. This function paints only background of `::first-line`. In
-// all other cases, the container box paints background.
+// Paint a line box. This function paints hit tests and backgrounds of
+// `::first-line`. In all other cases, the container box paints background.
inline void NGBoxFragmentPainter::PaintLineBox(
const NGPhysicalFragment& line_box_fragment,
const DisplayItemClient& display_item_client,
@@ -1046,30 +1166,29 @@ inline void NGBoxFragmentPainter::PaintLineBox(
if (paint_info.phase != PaintPhase::kForeground)
return;
- if (NGFragmentPainter::ShouldRecordHitTestData(paint_info,
- PhysicalFragment())) {
- RecordHitTestDataForLine(paint_info, child_offset, line_box_fragment,
- display_item_client);
+ if (ShouldRecordHitTestData(paint_info)) {
+ PhysicalRect border_box = line_box_fragment.LocalRect();
+ border_box.offset += child_offset;
+ paint_info.context.GetPaintController().RecordHitTestData(
+ display_item_client, PixelSnappedIntRect(border_box),
+ PhysicalFragment().EffectiveAllowedTouchAction());
+ }
+ if (NGLineBoxFragmentPainter::NeedsPaint(line_box_fragment)) {
+ NGLineBoxFragmentPainter line_box_painter(
+ line_box_fragment, line_box_paint_fragment, line_box_item,
+ PhysicalFragment(), paint_fragment_);
+ line_box_painter.PaintBackgroundBorderShadow(paint_info, child_offset);
}
-
- // Line boxes don't paint anything, except when its ::first-line style has
- // a background.
- if (!NGLineBoxFragmentPainter::NeedsPaint(line_box_fragment))
- return;
- NGLineBoxFragmentPainter line_box_painter(
- line_box_fragment, line_box_paint_fragment, line_box_item,
- PhysicalFragment(), paint_fragment_);
- line_box_painter.PaintBackgroundBorderShadow(paint_info, child_offset);
}
void NGBoxFragmentPainter::PaintLineBoxChildren(
- NGPaintFragment::ChildList line_boxes,
+ NGInlineCursor* children,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
// Only paint during the foreground/selection phases.
if (paint_info.phase != PaintPhase::kForeground &&
paint_info.phase != PaintPhase::kForcedColorsModeBackplate &&
- paint_info.phase != PaintPhase::kSelection &&
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip &&
paint_info.phase != PaintPhase::kMask &&
paint_info.phase != PaintPhase::kDescendantOutlinesOnly &&
@@ -1078,7 +1197,7 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
// The only way an inline could paint like this is if it has a layer.
const auto* layout_object = box_fragment_.GetLayoutObject();
- DCHECK(layout_object->IsLayoutBlock() ||
+ DCHECK(!layout_object || layout_object->IsLayoutBlock() ||
(layout_object->IsLayoutInline() && layout_object->HasLayer()));
// if (paint_info.phase == PaintPhase::kForeground && paint_info.IsPrinting())
@@ -1086,27 +1205,24 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
// paint_offset);
// If we have no lines then we have no work to do.
- if (line_boxes.IsEmpty())
+ if (!*children)
return;
- ScopedPaintTimingDetectorBlockPaintHook
- scoped_paint_timing_detector_block_paint_hook;
- const auto& layout_block = To<LayoutBlock>(*layout_object);
- if (paint_info.phase == PaintPhase::kForeground) {
- scoped_paint_timing_detector_block_paint_hook.EmplaceIfNeeded(
- layout_block,
- paint_info.context.GetPaintController().CurrentPaintChunkProperties());
+ if (paint_info.phase == PaintPhase::kForcedColorsModeBackplate &&
+ box_fragment_.GetDocument().InForcedColorsMode()) {
+ PaintBackplate(children, paint_info, paint_offset);
+ return;
}
- if (paint_info.phase == PaintPhase::kForcedColorsModeBackplate &&
- layout_block.GetDocument().InForcedColorsMode()) {
- PaintBackplate(line_boxes, paint_info, paint_offset);
+ if (UNLIKELY(children->IsItemCursor())) {
+ PaintLineBoxChildItems(children, paint_info, paint_offset);
return;
}
const bool is_horizontal = box_fragment_.Style().IsHorizontalWritingMode();
-
- for (const NGPaintFragment* line : line_boxes) {
+ for (; *children; children->MoveToNextSkippingChildren()) {
+ const NGPaintFragment* line = children->CurrentPaintFragment();
+ DCHECK(line);
const NGPhysicalFragment& child_fragment = line->PhysicalFragment();
DCHECK(!child_fragment.IsOutOfFlowPositioned());
if (child_fragment.IsFloating())
@@ -1140,14 +1256,67 @@ void NGBoxFragmentPainter::PaintLineBoxChildren(
}
}
-void NGBoxFragmentPainter::PaintBackplate(NGPaintFragment::ChildList line_boxes,
+void NGBoxFragmentPainter::PaintLineBoxChildItems(
+ NGInlineCursor* children,
+ const PaintInfo& paint_info,
+ const PhysicalOffset& paint_offset) {
+ const bool is_horizontal = box_fragment_.Style().IsHorizontalWritingMode();
+ for (; *children; children->MoveToNextSkippingChildren()) {
+ const NGFragmentItem* child_item = children->CurrentItem();
+ DCHECK(child_item);
+
+ // Check if CullRect intersects with this child, only in block direction
+ // because soft-wrap and <br> needs to paint outside of InkOverflow() in
+ // inline direction.
+ const PhysicalOffset& child_offset =
+ paint_offset + child_item->OffsetInContainerBlock();
+ const PhysicalRect child_rect = child_item->InkOverflow();
+ if (is_horizontal) {
+ LayoutUnit y = child_rect.offset.top + child_offset.top;
+ if (!paint_info.GetCullRect().IntersectsVerticalRange(
+ y, y + child_rect.size.height))
+ continue;
+ } else {
+ LayoutUnit x = child_rect.offset.left + child_offset.left;
+ if (!paint_info.GetCullRect().IntersectsHorizontalRange(
+ x, x + child_rect.size.width))
+ continue;
+ }
+
+ if (child_item->Type() == NGFragmentItem::kLine) {
+ const NGPhysicalLineBoxFragment* line_box_fragment =
+ child_item->LineBoxFragment();
+ DCHECK(line_box_fragment);
+ PaintLineBox(*line_box_fragment, *child_item,
+ /* line_box_paint_fragment */ nullptr, child_item,
+ paint_info, child_offset);
+ NGInlineCursor line_box_cursor = children->CursorForDescendants();
+ PaintInlineItems(paint_info, paint_offset,
+ child_item->OffsetInContainerBlock(), &line_box_cursor);
+ continue;
+ }
+
+ if (const NGPhysicalBoxFragment* child_fragment =
+ child_item->BoxFragment()) {
+ if (child_fragment->IsListMarker()) {
+ PaintBoxItem(*child_item, *child_fragment, *children, paint_info,
+ paint_offset);
+ continue;
+ }
+ }
+
+ NOTREACHED();
+ }
+}
+
+void NGBoxFragmentPainter::PaintBackplate(NGInlineCursor* line_boxes,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
if (paint_info.phase != PaintPhase::kForcedColorsModeBackplate)
return;
// Only paint backplates behind text when forced-color-adjust is auto.
- const ComputedStyle& style = line_boxes.front().Style();
+ const ComputedStyle& style = PhysicalFragment().Style();
if (style.ForcedColorAdjust() == EForcedColorAdjust::kNone)
return;
@@ -1229,7 +1398,7 @@ void NGBoxFragmentPainter::PaintTextChild(const NGPaintFragment& paint_fragment,
// Only paint during the foreground/selection phases.
if (paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelection &&
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip &&
paint_info.phase != PaintPhase::kMask)
return;
@@ -1241,24 +1410,20 @@ void NGBoxFragmentPainter::PaintTextChild(const NGPaintFragment& paint_fragment,
void NGBoxFragmentPainter::PaintTextItem(const NGInlineCursor& cursor,
const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
+ const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset) {
DCHECK(cursor.CurrentItem());
const NGFragmentItem& item = *cursor.CurrentItem();
DCHECK(item.IsText()) << item;
// Only paint during the foreground/selection phases.
if (paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelection &&
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip &&
paint_info.phase != PaintPhase::kMask)
return;
- // Need to check the style of each text items because they can have different
- // styles than its siblings if inline boxes are culled.
- if (UNLIKELY(!IsVisibleToPaint(item, item.Style())))
- return;
-
- NGTextFragmentPainter<NGInlineCursor> text_painter(cursor);
+ NGTextFragmentPainter<NGInlineCursor> text_painter(cursor, parent_offset);
text_painter.Paint(paint_info, paint_offset);
}
@@ -1269,7 +1434,8 @@ NGBoxFragmentPainter::MoveTo NGBoxFragmentPainter::PaintLineBoxItem(
DCHECK_EQ(item.Type(), NGFragmentItem::kLine);
DCHECK(items_);
// TODO(kojii): Check CullRect.
- const PhysicalOffset line_box__offset = paint_offset + item.Offset();
+ const PhysicalOffset line_box__offset =
+ paint_offset + item.OffsetInContainerBlock();
const NGPhysicalLineBoxFragment* line_box_fragment = item.LineBoxFragment();
DCHECK(line_box_fragment);
PaintLineBox(*line_box_fragment, item, /* line_box_paint_fragment */ nullptr,
@@ -1277,57 +1443,60 @@ NGBoxFragmentPainter::MoveTo NGBoxFragmentPainter::PaintLineBoxItem(
return kDontSkipChildren;
}
-NGBoxFragmentPainter::MoveTo NGBoxFragmentPainter::PaintBoxItem(
+// Paint non-culled box item.
+void NGBoxFragmentPainter::PaintBoxItem(
const NGFragmentItem& item,
+ const NGPhysicalBoxFragment& child_fragment,
+ const NGInlineCursor& cursor,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
DCHECK_EQ(item.Type(), NGFragmentItem::kBox);
-
- const ComputedStyle& style = item.Style();
- if (UNLIKELY(!IsVisibleToPaint(item, style)))
- return kSkipChildren;
-
- // Nothing to paint if this is a culled inline box. Proceed to its
- // descendants.
- const NGPhysicalBoxFragment* child_fragment = item.BoxFragment();
- if (!child_fragment)
- return kDontSkipChildren;
-
- DCHECK(!child_fragment->IsHiddenForPaint());
- if (child_fragment->HasSelfPaintingLayer() || child_fragment->IsFloating())
- return kSkipChildren;
+ DCHECK_EQ(&item, cursor.Current().Item());
+ DCHECK_EQ(item.BoxFragment(), &child_fragment);
+ DCHECK(!child_fragment.IsHiddenForPaint());
+ if (child_fragment.HasSelfPaintingLayer() || child_fragment.IsFloating())
+ return;
// TODO(kojii): Check CullRect.
- if (child_fragment->IsAtomicInline() || child_fragment->IsListMarker()) {
- if (FragmentRequiresLegacyFallback(*child_fragment)) {
- PaintInlineChildBoxUsingLegacyFallback(*child_fragment, paint_info);
- return kDontSkipChildren;
+ if (child_fragment.IsAtomicInline() || child_fragment.IsListMarker()) {
+ if (FragmentRequiresLegacyFallback(child_fragment)) {
+ PaintInlineChildBoxUsingLegacyFallback(child_fragment, paint_info);
+ return;
}
- NGBoxFragmentPainter(*child_fragment).PaintAllPhasesAtomically(paint_info);
- return kDontSkipChildren;
+ NGBoxFragmentPainter(child_fragment).PaintAllPhasesAtomically(paint_info);
+ return;
}
- NGInlineBoxFragmentPainter(item, *child_fragment)
+ DCHECK(child_fragment.IsInlineBox());
+ NGInlineBoxFragmentPainter(cursor, item, child_fragment)
.Paint(paint_info, paint_offset);
- return kDontSkipChildren;
}
-void NGBoxFragmentPainter::PaintAtomicInline(const PaintInfo& paint_info) {
- DCHECK(PhysicalFragment().IsAtomicInline());
- // Self-painting AtomicInlines should go to normal paint logic.
- DCHECK(!box_fragment_.HasSelfPaintingLayer());
+void NGBoxFragmentPainter::PaintBoxItem(const NGFragmentItem& item,
+ const NGInlineCursor& cursor,
+ const PaintInfo& paint_info,
+ const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset) {
+ DCHECK_EQ(item.Type(), NGFragmentItem::kBox);
+ DCHECK_EQ(&item, cursor.Current().Item());
- // Text clips are painted only for the direct inline children of the object
- // that has a text clip style on it, not block children.
- if (paint_info.phase == PaintPhase::kTextClip)
+ if (const NGPhysicalBoxFragment* child_fragment = item.BoxFragment()) {
+ PaintBoxItem(item, *child_fragment, cursor, paint_info, paint_offset);
return;
+ }
- PaintAllPhasesAtomically(paint_info);
+ // This |item| is a culled inline box.
+ DCHECK(item.GetLayoutObject()->IsLayoutInline());
+ NGInlineCursor children = cursor.CursorForDescendants();
+ // Pass the given |parent_offset| because culled inline boxes do not affect
+ // the sub-pixel snapping behavior. TODO(kojii): This is for the
+ // compatibility, we may want to revisit in future.
+ PaintInlineItems(paint_info, paint_offset, parent_offset, &children);
}
bool NGBoxFragmentPainter::IsPaintingScrollingBackground(
- const PaintInfo& paint_info) {
+ const PaintInfo& paint_info) const {
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return paint_info.IsPaintingScrollingBackground();
@@ -1361,27 +1530,43 @@ void NGBoxFragmentPainter::PaintTextClipMask(GraphicsContext& context,
bool object_has_multiple_boxes) {
PaintInfo paint_info(context, mask_rect, PaintPhase::kTextClip,
kGlobalPaintNormalPhase, 0);
- if (object_has_multiple_boxes) {
- DCHECK(paint_fragment_);
- PhysicalOffset local_offset = paint_fragment_->Offset();
- DCHECK(paint_fragment_);
- NGInlineBoxFragmentPainter inline_box_painter(*paint_fragment_);
- if (box_fragment_.Style().BoxDecorationBreak() ==
- EBoxDecorationBreak::kSlice) {
- LayoutUnit offset_on_line;
- LayoutUnit total_width;
- inline_box_painter.ComputeFragmentOffsetOnLine(
- box_fragment_.Style().Direction(), &offset_on_line, &total_width);
- LayoutSize line_offset(offset_on_line, LayoutUnit());
- local_offset -=
- PhysicalOffset(box_fragment_.Style().IsHorizontalWritingMode()
- ? line_offset
- : line_offset.TransposedSize());
- }
- inline_box_painter.Paint(paint_info, paint_offset - local_offset);
- } else {
+ if (!object_has_multiple_boxes) {
PaintObject(paint_info, paint_offset);
+ return;
}
+
+ if (paint_fragment_) {
+ NGInlineBoxFragmentPainter inline_box_painter(*paint_fragment_);
+ PaintTextClipMask(paint_info, paint_offset - paint_fragment_->Offset(),
+ &inline_box_painter);
+ return;
+ }
+
+ DCHECK(inline_box_cursor_);
+ DCHECK(box_item_);
+ NGInlineBoxFragmentPainter inline_box_painter(*inline_box_cursor_,
+ *box_item_);
+ PaintTextClipMask(paint_info,
+ paint_offset - box_item_->OffsetInContainerBlock(),
+ &inline_box_painter);
+}
+
+void NGBoxFragmentPainter::PaintTextClipMask(
+ const PaintInfo& paint_info,
+ PhysicalOffset paint_offset,
+ NGInlineBoxFragmentPainter* inline_box_painter) {
+ const ComputedStyle& style = box_fragment_.Style();
+ if (style.BoxDecorationBreak() == EBoxDecorationBreak::kSlice) {
+ LayoutUnit offset_on_line;
+ LayoutUnit total_width;
+ inline_box_painter->ComputeFragmentOffsetOnLine(
+ style.Direction(), &offset_on_line, &total_width);
+ if (style.IsHorizontalWritingMode())
+ paint_offset.left += offset_on_line;
+ else
+ paint_offset.top += offset_on_line;
+ }
+ inline_box_painter->Paint(paint_info, paint_offset);
}
PhysicalRect NGBoxFragmentPainter::AdjustRectForScrolledContent(
@@ -1421,219 +1606,249 @@ LayoutRectOutsets NGBoxFragmentPainter::ComputePadding() const {
BoxPainterBase::FillLayerInfo NGBoxFragmentPainter::GetFillLayerInfo(
const Color& color,
const FillLayer& bg_layer,
- BackgroundBleedAvoidance bleed_avoidance) const {
+ BackgroundBleedAvoidance bleed_avoidance,
+ bool is_painting_scrolling_background) const {
const NGBorderEdges& border_edges = BorderEdges();
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
return BoxPainterBase::FillLayerInfo(
fragment.GetLayoutObject()->GetDocument(), fragment.Style(),
fragment.HasOverflowClip(), color, bg_layer, bleed_avoidance,
+ LayoutObject::ShouldRespectImageOrientation(fragment.GetLayoutObject()),
border_edges.line_left, border_edges.line_right,
- fragment.GetLayoutObject()->IsInline());
+ fragment.GetLayoutObject()->IsLayoutInline(),
+ is_painting_scrolling_background);
+}
+
+bool NGBoxFragmentPainter::HitTestContext::AddNodeToResult(
+ Node* node,
+ const PhysicalRect& bounds_rect,
+ const PhysicalOffset& offset) const {
+ if (node && !result->InnerNode())
+ result->SetNodeAndPosition(node, location.Point() - offset);
+ return result->AddNodeToListBasedTestResult(node, location, bounds_rect) ==
+ kStopHitTesting;
}
-bool NGBoxFragmentPainter::IsInSelfHitTestingPhase(HitTestAction action) const {
- // TODO(layout-dev): We should set an IsContainingBlock flag on
- // NGPhysicalBoxFragment, instead of routing back to LayoutObject.
- if (const auto* box = ToLayoutBoxOrNull(PhysicalFragment().GetLayoutObject()))
- return box->IsInSelfHitTestingPhase(action);
- return action == kHitTestForeground;
+bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
+ const HitTestLocation& hit_test_location,
+ const PhysicalOffset& physical_offset,
+ HitTestAction action) {
+ HitTestContext hit_test(action, hit_test_location, physical_offset, &result);
+ return NodeAtPoint(hit_test, physical_offset);
}
bool NGBoxFragmentPainter::NodeAtPoint(HitTestResult& result,
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
+ const PhysicalOffset& inline_root_offset,
HitTestAction action) {
+ HitTestContext hit_test(action, hit_test_location, inline_root_offset,
+ &result);
+ return NodeAtPoint(hit_test, physical_offset);
+}
+
+bool NGBoxFragmentPainter::NodeAtPoint(const HitTestContext& hit_test,
+ const PhysicalOffset& physical_offset) {
const NGPhysicalBoxFragment& fragment = PhysicalFragment();
const PhysicalSize& size = box_fragment_.Size();
const ComputedStyle& style = box_fragment_.Style();
- bool hit_test_self = IsInSelfHitTestingPhase(action);
+ bool hit_test_self = fragment.IsInSelfHitTestingPhase(hit_test.action);
- // TODO(layout-dev): Add support for hit testing overflow controls once we
- // overflow has been implemented.
- // if (hit_test_self && HasOverflowClip() &&
- // HitTestOverflowControl(result, hit_test_location, physical_offset))
- // return true;
+ if (hit_test_self && box_fragment_.HasOverflowClip() &&
+ HitTestOverflowControl(hit_test, physical_offset))
+ return true;
- bool skip_children = result.GetHitTestRequest().GetStopNode() ==
- PhysicalFragment().GetLayoutObject();
+ const LayoutObject* layout_object = PhysicalFragment().GetLayoutObject();
+ bool skip_children =
+ layout_object &&
+ layout_object == hit_test.result->GetHitTestRequest().GetStopNode();
if (!skip_children && box_fragment_.ShouldClipOverflow()) {
// PaintLayer::HitTestContentsForFragments checked the fragments'
// foreground rect for intersection if a layer is self painting,
// so only do the overflow clip check here for non-self-painting layers.
if (!box_fragment_.HasSelfPaintingLayer() &&
- !hit_test_location.Intersects(PhysicalFragment().OverflowClipRect(
+ !hit_test.location.Intersects(PhysicalFragment().OverflowClipRect(
physical_offset, kExcludeOverlayScrollbarSizeForHitTesting))) {
skip_children = true;
}
if (!skip_children && style.HasBorderRadius()) {
PhysicalRect bounds_rect(physical_offset, size);
- skip_children = !hit_test_location.Intersects(
+ skip_children = !hit_test.location.Intersects(
style.GetRoundedInnerBorderFor(bounds_rect.ToLayoutRect()));
}
}
if (!skip_children) {
- PhysicalOffset scrolled_offset = physical_offset;
- if (box_fragment_.HasOverflowClip()) {
- scrolled_offset -= PhysicalOffset(
- PhysicalFragment().PixelSnappedScrolledContentOffset());
+ if (!box_fragment_.HasOverflowClip()) {
+ if (HitTestChildren(hit_test, physical_offset))
+ return true;
+ } else {
+ const PhysicalOffset scrolled_offset =
+ physical_offset -
+ PhysicalOffset(
+ PhysicalFragment().PixelSnappedScrolledContentOffset());
+ HitTestContext adjusted_hit_test(hit_test.action, hit_test.location,
+ scrolled_offset, hit_test.result);
+ if (HitTestChildren(adjusted_hit_test, scrolled_offset))
+ return true;
}
- if (HitTestChildren(result, hit_test_location, scrolled_offset, action))
- return true;
}
if (style.HasBorderRadius() &&
- HitTestClippedOutByBorder(hit_test_location, physical_offset))
+ HitTestClippedOutByBorder(hit_test.location, physical_offset))
return false;
// Now hit test ourselves.
- if (hit_test_self && VisibleToHitTestRequest(result.GetHitTestRequest())) {
+ if (hit_test_self &&
+ VisibleToHitTestRequest(hit_test.result->GetHitTestRequest())) {
PhysicalRect bounds_rect(physical_offset, size);
- if (UNLIKELY(result.GetHitTestRequest().GetType() &
+ if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) {
- bounds_rect = paint_fragment_->SelfInkOverflow();
+ bounds_rect = SelfInkOverflow();
bounds_rect.Move(physical_offset);
}
// TODO(kojii): Don't have good explanation why only inline box needs to
// snap, but matches to legacy and fixes crbug.com/976606.
if (fragment.IsInlineBox())
bounds_rect = PhysicalRect(PixelSnappedIntRect(bounds_rect));
- if (hit_test_location.Intersects(bounds_rect)) {
- Node* node = fragment.NodeForHitTest();
- if (!result.InnerNode() && node) {
- PhysicalOffset point = hit_test_location.Point() - physical_offset;
- result.SetNodeAndPosition(node, point);
- }
- if (result.AddNodeToListBasedTestResult(node, hit_test_location,
- bounds_rect) == kStopHitTesting) {
+ if (hit_test.location.Intersects(bounds_rect)) {
+ if (hit_test.AddNodeToResult(fragment.NodeForHitTest(), bounds_rect,
+ physical_offset))
return true;
- }
}
}
return false;
}
+bool NGBoxFragmentPainter::HitTestAllPhases(
+ HitTestResult& result,
+ const HitTestLocation& hit_test_location,
+ const PhysicalOffset& accumulated_offset,
+ HitTestFilter hit_test_filter) {
+ // Logic taken from LayoutObject::HitTestAllPhases().
+ HitTestContext hit_test(kHitTestForeground, hit_test_location,
+ accumulated_offset, &result);
+ bool inside = false;
+ if (hit_test_filter != kHitTestSelf) {
+ // First test the foreground layer (lines and inlines).
+ inside = NodeAtPoint(hit_test, accumulated_offset);
+
+ // Test floats next.
+ if (!inside) {
+ hit_test.action = kHitTestFloat;
+ inside = NodeAtPoint(hit_test, accumulated_offset);
+ }
+
+ // Finally test to see if the mouse is in the background (within a child
+ // block's background).
+ if (!inside) {
+ hit_test.action = kHitTestChildBlockBackgrounds;
+ inside = NodeAtPoint(hit_test, accumulated_offset);
+ }
+ }
+
+ // See if the pointer is inside us but not any of our descendants.
+ if (hit_test_filter != kHitTestDescendants && !inside) {
+ hit_test.action = kHitTestChildBlockBackground;
+ inside = NodeAtPoint(hit_test, accumulated_offset);
+ }
+
+ return inside;
+}
+
bool NGBoxFragmentPainter::VisibleToHitTestRequest(
const HitTestRequest& request) const {
return FragmentVisibleToHitTestRequest(box_fragment_, request);
}
bool NGBoxFragmentPainter::HitTestTextFragment(
- HitTestResult& result,
+ const HitTestContext& hit_test,
const NGInlineBackwardCursor& cursor,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction action) {
- if (action != kHitTestForeground)
+ const PhysicalOffset& physical_offset) {
+ if (hit_test.action != kHitTestForeground)
return false;
- const NGPaintFragment* text_paint_fragment = cursor.CurrentPaintFragment();
+ const NGPaintFragment* text_paint_fragment = cursor.Current().PaintFragment();
DCHECK(text_paint_fragment);
const auto& text_fragment =
To<NGPhysicalTextFragment>(text_paint_fragment->PhysicalFragment());
- PhysicalRect border_rect(physical_offset, text_fragment.Size());
+ if (!FragmentVisibleToHitTestRequest(text_fragment,
+ hit_test.result->GetHitTestRequest()))
+ return false;
// TODO(layout-dev): Clip to line-top/bottom.
+ PhysicalRect border_rect(physical_offset, text_fragment.Size());
PhysicalRect rect(PixelSnappedIntRect(border_rect));
- if (UNLIKELY(result.GetHitTestRequest().GetType() &
+ if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) {
rect = text_fragment.SelfInkOverflow();
rect.Move(border_rect.offset);
}
+ if (!hit_test.location.Intersects(rect))
+ return false;
- if (FragmentVisibleToHitTestRequest(text_fragment,
- result.GetHitTestRequest()) &&
- hit_test_location.Intersects(rect)) {
- Node* node = text_fragment.NodeForHitTest();
- if (!result.InnerNode() && node) {
- PhysicalOffset point = hit_test_location.Point() - physical_offset +
- text_paint_fragment->InlineOffsetToContainerBox();
- result.SetNodeAndPosition(node, point);
- }
-
- if (result.AddNodeToListBasedTestResult(node, hit_test_location, rect) ==
- kStopHitTesting) {
- return true;
- }
- }
-
- return false;
+ return hit_test.AddNodeToResult(
+ text_fragment.NodeForHitTest(), rect,
+ physical_offset - text_paint_fragment->OffsetInContainerBlock());
}
-bool NGBoxFragmentPainter::HitTestTextItem(
- HitTestResult& result,
- const NGFragmentItem& text_item,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction action) {
+bool NGBoxFragmentPainter::HitTestTextItem(const HitTestContext& hit_test,
+ const NGFragmentItem& text_item) {
DCHECK(text_item.IsText());
- if (action != kHitTestForeground)
+ if (hit_test.action != kHitTestForeground)
+ return false;
+ if (!IsVisibleToHitTest(text_item, hit_test.result->GetHitTestRequest()))
return false;
-
- PhysicalRect border_rect(physical_offset, text_item.Size());
// TODO(layout-dev): Clip to line-top/bottom.
+ const PhysicalOffset offset =
+ hit_test.inline_root_offset + text_item.OffsetInContainerBlock();
+ PhysicalRect border_rect(offset, text_item.Size());
PhysicalRect rect(PixelSnappedIntRect(border_rect));
- if (UNLIKELY(result.GetHitTestRequest().GetType() &
+ if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
HitTestRequest::kHitTestVisualOverflow)) {
rect = text_item.SelfInkOverflow();
rect.Move(border_rect.offset);
}
+ if (!hit_test.location.Intersects(rect))
+ return false;
- if (IsVisibleToHitTest(text_item, result.GetHitTestRequest()) &&
- hit_test_location.Intersects(rect)) {
- Node* node = text_item.NodeForHitTest();
- if (!result.InnerNode() && node) {
- PhysicalOffset point =
- hit_test_location.Point() - physical_offset + text_item.Offset();
- result.SetNodeAndPosition(node, point);
- }
-
- if (result.AddNodeToListBasedTestResult(node, hit_test_location, rect) ==
- kStopHitTesting) {
- return true;
- }
- }
-
- return false;
+ return hit_test.AddNodeToResult(text_item.NodeForHitTest(), rect,
+ hit_test.inline_root_offset);
}
// Replicates logic in legacy InlineFlowBox::NodeAtPoint().
bool NGBoxFragmentPainter::HitTestLineBoxFragment(
- HitTestResult& result,
+ const HitTestContext& hit_test,
const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction action) {
- if (HitTestChildren(result, cursor.CursorForDescendants(), hit_test_location,
- physical_offset, action))
+ const PhysicalOffset& physical_offset) {
+ if (HitTestChildren(hit_test, cursor.CursorForDescendants(), physical_offset))
return true;
- if (action != kHitTestForeground)
+ if (hit_test.action != kHitTestForeground)
return false;
- if (!VisibleToHitTestRequest(result.GetHitTestRequest()))
+ if (!VisibleToHitTestRequest(hit_test.result->GetHitTestRequest()))
return false;
const PhysicalOffset overflow_location =
- cursor.CurrentSelfInkOverflow().offset + physical_offset;
- if (HitTestClippedOutByBorder(hit_test_location, overflow_location))
+ cursor.Current().SelfInkOverflow().offset + physical_offset;
+ if (HitTestClippedOutByBorder(hit_test.location, overflow_location))
return false;
const PhysicalRect bounds_rect(physical_offset, fragment.Size());
const ComputedStyle& containing_box_style = box_fragment_.Style();
if (containing_box_style.HasBorderRadius() &&
- !hit_test_location.Intersects(containing_box_style.GetRoundedBorderFor(
- bounds_rect.ToLayoutRect()))) {
+ !hit_test.location.Intersects(
+ containing_box_style.GetRoundedBorderFor(bounds_rect.ToLayoutRect())))
return false;
- }
// Now hit test ourselves.
- if (!hit_test_location.Intersects(bounds_rect))
+ if (!hit_test.location.Intersects(bounds_rect))
return false;
// Floats will be hit-tested in |kHitTestFloat| phase, but
@@ -1643,123 +1858,207 @@ bool NGBoxFragmentPainter::HitTestLineBoxFragment(
// restructuring. Changing the caller logic isn't easy because currently
// floats are in the bounds of line boxes only in NG.
if (fragment.HasFloatingDescendantsForPaint()) {
- DCHECK_NE(action, kHitTestFloat);
- if (HitTestChildren(result, cursor.CursorForDescendants(),
- hit_test_location, physical_offset, kHitTestFloat)) {
+ DCHECK_NE(hit_test.action, kHitTestFloat);
+ HitTestContext hit_test_float = hit_test;
+ hit_test_float.action = kHitTestFloat;
+ if (HitTestChildren(hit_test_float, cursor.CursorForDescendants(),
+ physical_offset))
return false;
- }
}
- Node* node = fragment.NodeForHitTest();
- if (!result.InnerNode() && node) {
- const PhysicalOffset point =
- hit_test_location.Point() - physical_offset + cursor.CurrentOffset();
- result.SetNodeAndPosition(node, point);
- }
- return result.AddNodeToListBasedTestResult(node, hit_test_location,
- bounds_rect) == kStopHitTesting;
+ return hit_test.AddNodeToResult(
+ fragment.NodeForHitTest(), bounds_rect,
+ physical_offset - cursor.Current().OffsetInContainerBlock());
}
bool NGBoxFragmentPainter::HitTestChildBoxFragment(
- HitTestResult& result,
+ const HitTestContext& hit_test,
const NGPhysicalBoxFragment& fragment,
- const NGInlineBackwardCursor& cursor,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction action) {
+ const NGInlineBackwardCursor& backward_cursor,
+ const PhysicalOffset& physical_offset) {
// Note: Floats should only be hit tested in the |kHitTestFloat| phase, so we
// shouldn't enter a float when |action| doesn't match. However, as floats may
// scatter around in the entire inline formatting context, we should always
// enter non-floating inline child boxes to search for floats in the
// |kHitTestFloat| phase, unless the child box forms another context.
- if (fragment.IsFloating() && action != kHitTestFloat)
+ if (fragment.IsFloating() && hit_test.action != kHitTestFloat)
return false;
if (!FragmentRequiresLegacyFallback(fragment)) {
- // TODO(layout-dev): Implement HitTestAllPhases in NG after we stop
- // falling back to legacy for child atomic inlines and floats.
DCHECK(!fragment.IsAtomicInline());
DCHECK(!fragment.IsFloating());
- if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
+ if (const NGPaintFragment* paint_fragment =
+ backward_cursor.Current().PaintFragment()) {
+ if (fragment.IsInlineBox()) {
+ return NGBoxFragmentPainter(*paint_fragment)
+ .NodeAtPoint(hit_test, physical_offset);
+ }
+ // When traversing into a different inline formatting context,
+ // |inline_root_offset| needs to be updated.
return NGBoxFragmentPainter(*paint_fragment)
- .NodeAtPoint(result, hit_test_location, physical_offset, action);
+ .NodeAtPoint(*hit_test.result, hit_test.location, physical_offset,
+ hit_test.action);
}
- const NGFragmentItem* item = cursor.CurrentItem();
+ NGInlineCursor cursor(backward_cursor);
+ const NGFragmentItem* item = cursor.Current().Item();
DCHECK(item);
DCHECK_EQ(item->BoxFragment(), &fragment);
- NGInlineCursor descendants = cursor.CursorForDescendants();
- return NGBoxFragmentPainter(*item, fragment, &descendants)
- .NodeAtPoint(result, hit_test_location, physical_offset, action);
+ if (fragment.IsInlineBox()) {
+ return NGBoxFragmentPainter(cursor, *item, fragment)
+ .NodeAtPoint(hit_test, physical_offset);
+ }
+ // When traversing into a different inline formatting context,
+ // |inline_root_offset| needs to be updated.
+ return NGBoxFragmentPainter(cursor, *item, fragment)
+ .NodeAtPoint(*hit_test.result, hit_test.location, physical_offset,
+ hit_test.action);
}
- if (fragment.IsInline() && action != kHitTestForeground)
+ if (fragment.IsInline() && hit_test.action != kHitTestForeground)
return false;
- LayoutBox* const layout_box = ToLayoutBox(fragment.GetMutableLayoutObject());
+ if (fragment.IsPaintedAtomically()) {
+ return HitTestAllPhasesInFragment(fragment, hit_test.location,
+ physical_offset, hit_test.result);
+ }
- // https://www.w3.org/TR/CSS22/zindex.html#painting-order
- // Hit test all phases of inline blocks, inline tables, replaced elements and
- // non-positioned floats as if they created their own stacking contexts.
- if (fragment.IsAtomicInline() || fragment.IsFloating()) {
- return layout_box->HitTestAllPhases(result, hit_test_location,
- physical_offset);
+ return fragment.GetMutableLayoutObject()->NodeAtPoint(
+ *hit_test.result, hit_test.location, physical_offset, hit_test.action);
+}
+
+bool NGBoxFragmentPainter::HitTestChildBoxItem(
+ const HitTestContext& hit_test,
+ const NGFragmentItem& item,
+ const NGInlineBackwardCursor& cursor) {
+ DCHECK_EQ(&item, cursor.Current().Item());
+
+ if (const NGPhysicalBoxFragment* child_fragment = item.BoxFragment()) {
+ const PhysicalOffset child_offset =
+ hit_test.inline_root_offset + item.OffsetInContainerBlock();
+ return HitTestChildBoxFragment(hit_test, *child_fragment, cursor,
+ child_offset);
+ }
+
+ DCHECK(item.GetLayoutObject()->IsLayoutInline());
+ DCHECK(!ToLayoutInline(item.GetLayoutObject())->ShouldCreateBoxFragment());
+ if (NGInlineCursor descendants = cursor.CursorForDescendants()) {
+ if (HitTestItemsChildren(hit_test, descendants))
+ return true;
}
- return layout_box->NodeAtPoint(result, hit_test_location, physical_offset,
- action);
+
+ // Now hit test ourselves.
+ if (hit_test.action == kHitTestForeground &&
+ IsVisibleToHitTest(item, hit_test.result->GetHitTestRequest())) {
+ const PhysicalOffset child_offset =
+ hit_test.inline_root_offset + item.OffsetInContainerBlock();
+ PhysicalRect bounds_rect(child_offset, item.Size());
+ if (UNLIKELY(hit_test.result->GetHitTestRequest().GetType() &
+ HitTestRequest::kHitTestVisualOverflow)) {
+ bounds_rect = item.SelfInkOverflow();
+ bounds_rect.Move(child_offset);
+ }
+ // TODO(kojii): Don't have good explanation why only inline box needs to
+ // snap, but matches to legacy and fixes crbug.com/976606.
+ bounds_rect = PhysicalRect(PixelSnappedIntRect(bounds_rect));
+ if (hit_test.location.Intersects(bounds_rect)) {
+ if (hit_test.AddNodeToResult(item.NodeForHitTest(), bounds_rect,
+ child_offset))
+ return true;
+ }
+ }
+
+ return false;
}
bool NGBoxFragmentPainter::HitTestChildren(
- HitTestResult& result,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& accumulated_offset,
- HitTestAction action) {
+ const HitTestContext& hit_test,
+ const PhysicalOffset& accumulated_offset) {
if (paint_fragment_) {
NGInlineCursor cursor(*paint_fragment_);
- return HitTestChildren(result, cursor, hit_test_location,
- accumulated_offset, action);
+ return HitTestChildren(hit_test, cursor, accumulated_offset);
}
- if (UNLIKELY(descendants_)) {
- if (!*descendants_)
- return false;
- return HitTestChildren(result, *descendants_, hit_test_location,
- accumulated_offset, action);
+ if (UNLIKELY(inline_box_cursor_)) {
+ NGInlineCursor descendants = inline_box_cursor_->CursorForDescendants();
+ if (descendants)
+ return HitTestChildren(hit_test, descendants, accumulated_offset);
+ return false;
}
if (items_) {
NGInlineCursor cursor(*items_);
- return HitTestChildren(result, cursor, hit_test_location,
- accumulated_offset, action);
+ return HitTestChildren(hit_test, cursor, accumulated_offset);
}
- NOTREACHED();
- return false;
+ // Check descendants of this fragment because floats may be in the
+ // |NGFragmentItems| of the descendants.
+ if (hit_test.action == kHitTestFloat &&
+ box_fragment_.HasFloatingDescendantsForPaint() &&
+ RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ return HitTestFloatingChildren(hit_test, box_fragment_, accumulated_offset);
+ }
+
+ if (hit_test.action == kHitTestFloat) {
+ return box_fragment_.HasFloatingDescendantsForPaint() &&
+ HitTestFloatingChildren(hit_test, box_fragment_, accumulated_offset);
+ }
+ return HitTestBlockChildren(*hit_test.result, hit_test.location,
+ accumulated_offset, hit_test.action);
}
bool NGBoxFragmentPainter::HitTestChildren(
- HitTestResult& result,
+ const HitTestContext& hit_test,
const NGInlineCursor& children,
+ const PhysicalOffset& accumulated_offset) {
+ if (children.IsPaintFragmentCursor())
+ return HitTestPaintFragmentChildren(hit_test, children, accumulated_offset);
+ if (children.IsItemCursor())
+ return HitTestItemsChildren(hit_test, children);
+ // Hits nothing if there were no children.
+ return false;
+}
+
+bool NGBoxFragmentPainter::HitTestBlockChildren(
+ HitTestResult& result,
const HitTestLocation& hit_test_location,
- const PhysicalOffset& accumulated_offset,
+ PhysicalOffset accumulated_offset,
HitTestAction action) {
- if (children.IsPaintFragmentCursor()) {
- return HitTestPaintFragmentChildren(result, children, hit_test_location,
- accumulated_offset, action);
- }
- if (children.IsItemCursor()) {
- return HitTestItemsChildren(result, children, hit_test_location,
- accumulated_offset, action);
+ if (action == kHitTestChildBlockBackgrounds)
+ action = kHitTestChildBlockBackground;
+ auto children = box_fragment_.Children();
+ for (const NGLink& child : base::Reversed(children)) {
+ const auto& block_child = To<NGPhysicalBoxFragment>(*child);
+ if (block_child.HasSelfPaintingLayer() || block_child.IsFloating())
+ continue;
+
+ const PhysicalOffset child_offset = accumulated_offset + child.offset;
+
+ if (block_child.IsPaintedAtomically()) {
+ if (HitTestAllPhasesInFragment(block_child, hit_test_location,
+ child_offset, &result))
+ return true;
+
+ continue;
+ }
+
+ if (NodeAtPointInFragment(block_child, hit_test_location, child_offset,
+ action, &result)) {
+ if (const LayoutObject* child_object = block_child.GetLayoutObject()) {
+ child_object->UpdateHitTestResult(
+ result, hit_test_location.Point() - accumulated_offset);
+ }
+ return true;
+ }
}
- // Hits nothing if there were no children.
+
return false;
}
bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
- HitTestResult& result,
+ const HitTestContext& hit_test,
const NGInlineCursor& children,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& accumulated_offset,
- HitTestAction action) {
+ const PhysicalOffset& accumulated_offset) {
DCHECK(children.IsPaintFragmentCursor());
for (NGInlineBackwardCursor cursor(children); cursor;) {
- const NGPaintFragment* child_paint_fragment = cursor.CurrentPaintFragment();
+ const NGPaintFragment* child_paint_fragment =
+ cursor.Current().PaintFragment();
DCHECK(child_paint_fragment);
const NGPhysicalFragment& child_fragment =
child_paint_fragment->PhysicalFragment();
@@ -1771,30 +2070,29 @@ bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
const PhysicalOffset child_offset =
child_paint_fragment->Offset() + accumulated_offset;
if (child_fragment.Type() == NGPhysicalFragment::kFragmentBox) {
- if (HitTestChildBoxFragment(
- result, To<NGPhysicalBoxFragment>(child_fragment), cursor,
- hit_test_location, child_offset, action))
+ if (HitTestChildBoxFragment(hit_test,
+ To<NGPhysicalBoxFragment>(child_fragment),
+ cursor, child_offset))
return true;
} else if (child_fragment.Type() == NGPhysicalFragment::kFragmentLineBox) {
- if (HitTestLineBoxFragment(
- result, To<NGPhysicalLineBoxFragment>(child_fragment), cursor,
- hit_test_location, child_offset, action))
+ if (HitTestLineBoxFragment(hit_test,
+ To<NGPhysicalLineBoxFragment>(child_fragment),
+ cursor, child_offset))
return true;
} else if (child_fragment.Type() == NGPhysicalFragment::kFragmentText) {
- if (HitTestTextFragment(result, cursor, hit_test_location, child_offset,
- action))
+ if (HitTestTextFragment(hit_test, cursor, child_offset))
return true;
}
cursor.MoveToPreviousSibling();
- if (child_fragment.IsInline() && action == kHitTestForeground) {
+ if (child_fragment.IsInline() && hit_test.action == kHitTestForeground) {
// Hit test culled inline boxes between |fragment| and its parent
// fragment.
const NGPaintFragment* previous_sibling =
- cursor ? cursor.CurrentPaintFragment() : nullptr;
- if (HitTestCulledInlineAncestors(result, *child_paint_fragment,
- previous_sibling, hit_test_location,
+ cursor ? cursor.Current().PaintFragment() : nullptr;
+ if (HitTestCulledInlineAncestors(*hit_test.result, *child_paint_fragment,
+ previous_sibling, hit_test.location,
child_offset))
return true;
}
@@ -1804,44 +2102,142 @@ bool NGBoxFragmentPainter::HitTestPaintFragmentChildren(
}
bool NGBoxFragmentPainter::HitTestItemsChildren(
- HitTestResult& result,
- const NGInlineCursor& children,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& accumulated_offset,
- HitTestAction action) {
+ const HitTestContext& hit_test,
+ const NGInlineCursor& children) {
DCHECK(children.IsItemCursor());
for (NGInlineBackwardCursor cursor(children); cursor;) {
- const NGFragmentItem* item = cursor.CurrentItem();
+ const NGFragmentItem* item = cursor.Current().Item();
DCHECK(item);
if (item->HasSelfPaintingLayer()) {
cursor.MoveToPreviousSibling();
continue;
}
- const PhysicalOffset child_offset = item->Offset() + accumulated_offset;
if (item->IsText()) {
- if (HitTestTextItem(result, *item, hit_test_location, child_offset,
- action))
+ if (HitTestTextItem(hit_test, *item))
return true;
} else if (item->Type() == NGFragmentItem::kLine) {
const NGPhysicalLineBoxFragment* child_fragment = item->LineBoxFragment();
DCHECK(child_fragment);
- if (HitTestLineBoxFragment(result, *child_fragment, cursor,
- hit_test_location, child_offset, action))
+ const PhysicalOffset child_offset =
+ hit_test.inline_root_offset + item->OffsetInContainerBlock();
+ if (HitTestLineBoxFragment(hit_test, *child_fragment, cursor,
+ child_offset))
return true;
} else if (item->Type() == NGFragmentItem::kBox) {
- if (const NGPhysicalBoxFragment* child_fragment = item->BoxFragment()) {
- if (HitTestChildBoxFragment(result, *child_fragment, cursor,
- hit_test_location, child_offset, action))
- return true;
- }
+ if (HitTestChildBoxItem(hit_test, *item, cursor))
+ return true;
} else {
NOTREACHED();
}
cursor.MoveToPreviousSibling();
+ }
+
+ return false;
+}
- // TODO(kojii): Implement hit-testing culled inline box.
+bool NGBoxFragmentPainter::HitTestFloatingChildren(
+ const HitTestContext& hit_test,
+ const NGPhysicalContainerFragment& container,
+ const PhysicalOffset& accumulated_offset) {
+ DCHECK_EQ(hit_test.action, kHitTestFloat);
+ DCHECK(container.HasFloatingDescendantsForPaint());
+
+ if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(&container)) {
+ if (const NGFragmentItems* items = box->Items()) {
+ NGInlineCursor children(*items);
+ return HitTestFloatingChildItems(hit_test, children, accumulated_offset);
+ }
+ }
+
+ auto children = container.Children();
+ for (const NGLink& child : base::Reversed(children)) {
+ const NGPhysicalFragment& child_fragment = *child.fragment;
+ if (child_fragment.HasSelfPaintingLayer())
+ continue;
+
+ const PhysicalOffset child_offset = accumulated_offset + child.offset;
+
+ if (child_fragment.IsFloating()) {
+ if (HitTestAllPhasesInFragment(To<NGPhysicalBoxFragment>(child_fragment),
+ hit_test.location, child_offset,
+ hit_test.result))
+ return true;
+ continue;
+ }
+
+ if (child_fragment.IsPaintedAtomically())
+ continue;
+
+ const auto* child_container =
+ DynamicTo<NGPhysicalContainerFragment>(&child_fragment);
+ if (!child_container || !child_container->HasFloatingDescendantsForPaint())
+ continue;
+
+ if (child_container->HasOverflowClip()) {
+ // We need to properly visit this fragment for hit-testing, rather than
+ // jumping directly to its children (which is what we normally do when
+ // looking for floats), in order to set up the clip rectangle.
+ if (child_container->CanTraverse()) {
+ if (NGBoxFragmentPainter(*To<NGPhysicalBoxFragment>(child_container))
+ .NodeAtPoint(*hit_test.result, hit_test.location, child_offset,
+ kHitTestFloat))
+ return true;
+ } else if (child_fragment.GetMutableLayoutObject()->NodeAtPoint(
+ *hit_test.result, hit_test.location, child_offset,
+ kHitTestFloat)) {
+ return true;
+ }
+ continue;
+ }
+
+ if (HitTestFloatingChildren(hit_test, *child_container, child_offset))
+ return true;
+ }
+ return false;
+}
+
+bool NGBoxFragmentPainter::HitTestFloatingChildItems(
+ const HitTestContext& hit_test,
+ const NGInlineCursor& children,
+ const PhysicalOffset& accumulated_offset) {
+ for (NGInlineBackwardCursor cursor(children); cursor;
+ cursor.MoveToPreviousSibling()) {
+ const NGFragmentItem* item = cursor.Current().Item();
+ DCHECK(item);
+ if (item->Type() == NGFragmentItem::kBox) {
+ if (const NGPhysicalBoxFragment* child_box = item->BoxFragment()) {
+ if (child_box->HasSelfPaintingLayer())
+ continue;
+
+ const PhysicalOffset child_offset =
+ accumulated_offset + item->OffsetInContainerBlock();
+ if (child_box->IsFloating()) {
+ if (HitTestAllPhasesInFragment(*child_box, hit_test.location,
+ child_offset, hit_test.result))
+ return true;
+ continue;
+ }
+
+ // Look into descendants of all inline boxes because inline boxes do not
+ // have |HasFloatingDescendantsForPaint()| flag.
+ if (!child_box->IsInlineBox())
+ continue;
+ }
+ DCHECK(item->GetLayoutObject()->IsLayoutInline());
+ } else if (item->Type() == NGFragmentItem::kLine) {
+ const NGPhysicalLineBoxFragment* child_line = item->LineBoxFragment();
+ DCHECK(child_line);
+ if (!child_line->HasFloatingDescendantsForPaint())
+ continue;
+ } else {
+ continue;
+ }
+
+ NGInlineCursor descendants = cursor.CursorForDescendants();
+ if (HitTestFloatingChildItems(hit_test, descendants, accumulated_offset))
+ return true;
}
return false;
@@ -1858,4 +2254,13 @@ bool NGBoxFragmentPainter::HitTestClippedOutByBorder(
rect.ToLayoutRect(), border_edges.line_left, border_edges.line_right));
}
+bool NGBoxFragmentPainter::HitTestOverflowControl(
+ const HitTestContext& hit_test,
+ PhysicalOffset accumulated_offset) {
+ const auto* layout_box = ToLayoutBoxOrNull(box_fragment_.GetLayoutObject());
+ return layout_box &&
+ layout_box->HitTestOverflowControl(*hit_test.result, hit_test.location,
+ accumulated_offset);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
index 08fd0e73eda..5fe1f5fe9a1 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/layout/api/hit_test_action.h"
#include "third_party/blink/renderer/core/layout/background_bleed_avoidance.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/paint/box_painter_base.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -24,6 +25,7 @@ class HitTestResult;
class NGFragmentItems;
class NGInlineCursor;
class NGInlineBackwardCursor;
+class NGInlineBoxFragmentPainter;
class NGPhysicalFragment;
class ScopedPaintState;
struct PaintInfo;
@@ -41,9 +43,9 @@ class NGBoxFragmentPainter : public BoxPainterBase {
// Construct for an inline formatting context.
NGBoxFragmentPainter(const NGPaintFragment&);
// Construct for an inline box.
- NGBoxFragmentPainter(const NGFragmentItem& item,
- const NGPhysicalBoxFragment& fragment,
- NGInlineCursor* descendants);
+ NGBoxFragmentPainter(const NGInlineCursor& inline_box_cursor,
+ const NGFragmentItem& item,
+ const NGPhysicalBoxFragment& fragment);
void Paint(const PaintInfo&);
void PaintObject(const PaintInfo&,
@@ -58,6 +60,16 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const HitTestLocation& hit_test_location,
const PhysicalOffset& physical_offset,
HitTestAction);
+ bool NodeAtPoint(HitTestResult&,
+ const HitTestLocation& hit_test_location,
+ const PhysicalOffset& physical_offset,
+ const PhysicalOffset& inline_root_offset,
+ HitTestAction);
+
+ bool HitTestAllPhases(HitTestResult&,
+ const HitTestLocation&,
+ const PhysicalOffset& accumulated_offset,
+ HitTestFilter = kHitTestAll);
protected:
LayoutRectOutsets ComputeBorders() const override;
@@ -65,12 +77,17 @@ class NGBoxFragmentPainter : public BoxPainterBase {
BoxPainterBase::FillLayerInfo GetFillLayerInfo(
const Color&,
const FillLayer&,
- BackgroundBleedAvoidance) const override;
+ BackgroundBleedAvoidance,
+ bool is_painting_scrolling_background) const override;
+ bool IsPaintingScrollingBackground(const PaintInfo&) const override;
void PaintTextClipMask(GraphicsContext&,
const IntRect& mask_rect,
const PhysicalOffset& paint_offset,
bool object_has_multiple_boxes) override;
+ void PaintTextClipMask(const PaintInfo& paint_info,
+ PhysicalOffset paint_offset,
+ NGInlineBoxFragmentPainter* inline_box_painter);
PhysicalRect AdjustRectForScrolledContent(
const PaintInfo&,
const BoxPainterBase::FillLayerInfo&,
@@ -80,10 +97,10 @@ class NGBoxFragmentPainter : public BoxPainterBase {
NGBoxFragmentPainter(const NGPhysicalBoxFragment&,
const DisplayItemClient& display_item_client,
const NGPaintFragment* = nullptr,
- NGInlineCursor* descendants = nullptr);
+ const NGInlineCursor* inline_box_cursor = nullptr,
+ const NGFragmentItem* = nullptr);
enum MoveTo { kDontSkipChildren, kSkipChildren };
- bool IsPaintingScrollingBackground(const PaintInfo&);
bool ShouldPaint(const ScopedPaintState&) const;
void PaintBoxDecorationBackground(const PaintInfo&,
@@ -93,24 +110,27 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const PhysicalRect&,
const DisplayItemClient&);
void PaintColumnRules(const PaintInfo&, const PhysicalOffset& paint_offset);
- bool BackgroundIsKnownToBeOpaque(const PaintInfo&);
void PaintInternal(const PaintInfo&);
void PaintAllPhasesAtomically(const PaintInfo&);
- void PaintBlockChildren(const PaintInfo&);
+ void PaintBlockChildren(const PaintInfo&, PhysicalOffset);
void PaintInlineItems(const PaintInfo&,
const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset,
NGInlineCursor* cursor);
- void PaintLineBoxChildren(NGPaintFragment::ChildList,
+ void PaintLineBoxChildren(NGInlineCursor* children,
const PaintInfo&,
const PhysicalOffset& paint_offset);
+ void PaintLineBoxChildItems(NGInlineCursor* children,
+ const PaintInfo&,
+ const PhysicalOffset& paint_offset);
void PaintLineBox(const NGPhysicalFragment& line_box_fragment,
const DisplayItemClient& display_item_client,
const NGPaintFragment* line_box_paint_fragment,
const NGFragmentItem* line_box_item,
const PaintInfo&,
const PhysicalOffset& paint_offset);
- void PaintBackplate(NGPaintFragment::ChildList,
+ void PaintBackplate(NGInlineCursor* descendants,
const PaintInfo&,
const PhysicalOffset& paint_offset);
void PaintInlineChildren(NGPaintFragment::ChildList,
@@ -126,97 +146,128 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const PhysicalOffset& paint_offset);
void PaintTextItem(const NGInlineCursor& cursor,
const PaintInfo&,
- const PhysicalOffset& paint_offset);
+ const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset);
MoveTo PaintLineBoxItem(const NGFragmentItem& item,
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset);
- MoveTo PaintBoxItem(const NGFragmentItem& item,
- const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset);
+ void PaintBoxItem(const NGFragmentItem& item,
+ const NGPhysicalBoxFragment& child_fragment,
+ const NGInlineCursor& cursor,
+ const PaintInfo& paint_info,
+ const PhysicalOffset& paint_offset);
+ void PaintBoxItem(const NGFragmentItem& item,
+ const NGInlineCursor& cursor,
+ const PaintInfo& paint_info,
+ const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset);
+ void PaintFloatingItems(const PaintInfo&, NGInlineCursor* cursor);
void PaintFloatingChildren(const NGPhysicalContainerFragment&,
const PaintInfo& paint_info,
const PaintInfo& float_paint_info);
void PaintFloats(const PaintInfo&);
void PaintMask(const PaintInfo&, const PhysicalOffset& paint_offset);
- void PaintAtomicInline(const PaintInfo&);
void PaintBackground(const PaintInfo&,
const PhysicalRect&,
const Color& background_color,
BackgroundBleedAvoidance = kBackgroundBleedNone);
void PaintCarets(const PaintInfo&, const PhysicalOffset& paint_offset);
- // Paint a scroll hit test display item and record scroll hit test data. This
- // should be called in the background paint phase even if there is no other
- // painted content.
+ // This should be called in the background paint phase even if there is no
+ // other painted content.
void RecordScrollHitTestData(const PaintInfo&,
const DisplayItemClient& background_client);
- void RecordHitTestDataForLine(const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset,
- const NGPhysicalFragment& line,
- const DisplayItemClient& display_item_client);
+ bool ShouldRecordHitTestData(const PaintInfo&);
- bool IsInSelfHitTestingPhase(HitTestAction) const;
bool VisibleToHitTestRequest(const HitTestRequest&) const;
+ // This struct has common data needed while traversing trees for the hit
+ // testing.
+ struct HitTestContext {
+ STACK_ALLOCATED();
+
+ public:
+ HitTestContext(HitTestAction action,
+ const HitTestLocation& location,
+ const PhysicalOffset& inline_root_offset,
+ HitTestResult* result)
+ : action(action),
+ location(location),
+ inline_root_offset(inline_root_offset),
+ result(result) {}
+
+ // Add |node| to |HitTestResult|. Returns true if the hit-testing should
+ // stop.
+ bool AddNodeToResult(Node* node,
+ const PhysicalRect& bounds_rect,
+ const PhysicalOffset& offset) const;
+
+ HitTestAction action;
+ const HitTestLocation& location;
+ // When traversing within an inline formatting context, this member
+ // represents the offset of the root of the inline formatting context.
+ PhysicalOffset inline_root_offset;
+ // The result is set to this member, but its address does not change during
+ // the traversal.
+ HitTestResult* result;
+ };
+
// Hit tests the children of a container fragment, which is either
// |box_fragment_|, or one of its child line box fragments.
// @param physical_offset Physical offset of the container fragment's content
// box in paint layer. Note that this includes scrolling offset when the
// container has 'overflow: scroll'.
- bool HitTestChildren(HitTestResult&,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction);
- bool HitTestChildren(HitTestResult&,
+ bool NodeAtPoint(const HitTestContext& hit_test,
+ const PhysicalOffset& physical_offset);
+ bool HitTestChildren(const HitTestContext& hit_test,
+ const PhysicalOffset& physical_offset);
+ bool HitTestChildren(const HitTestContext& hit_test,
const NGInlineCursor& children,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction);
- bool HitTestPaintFragmentChildren(HitTestResult&,
- const NGInlineCursor& children,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction);
- bool HitTestItemsChildren(HitTestResult&,
- const NGInlineCursor& children,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
+ const PhysicalOffset& physical_offset);
+ bool HitTestBlockChildren(HitTestResult&,
+ const HitTestLocation&,
+ PhysicalOffset,
HitTestAction);
+ bool HitTestPaintFragmentChildren(const HitTestContext& hit_test,
+ const NGInlineCursor& children,
+ const PhysicalOffset& physical_offset);
+ bool HitTestItemsChildren(const HitTestContext& hit_test,
+ const NGInlineCursor& children);
+ bool HitTestFloatingChildren(const HitTestContext& hit_test,
+ const NGPhysicalContainerFragment& container,
+ const PhysicalOffset& accumulated_offset);
+ bool HitTestFloatingChildItems(const HitTestContext& hit_test,
+ const NGInlineCursor& children,
+ const PhysicalOffset& accumulated_offset);
// Hit tests a box fragment, which is a child of either |box_fragment_|, or
// one of its child line box fragments.
// @param physical_offset Physical offset of the given box fragment in the
// paint layer.
- bool HitTestChildBoxFragment(HitTestResult&,
+ bool HitTestChildBoxFragment(const HitTestContext& hit_test,
const NGPhysicalBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction);
+ const PhysicalOffset& physical_offset);
+ bool HitTestChildBoxItem(const HitTestContext& hit_test,
+ const NGFragmentItem& item,
+ const NGInlineBackwardCursor& cursor);
// Hit tests the given text fragment.
// @param physical_offset Physical offset of the text fragment in paint layer.
- bool HitTestTextFragment(HitTestResult&,
+ bool HitTestTextFragment(const HitTestContext& hit_test,
const NGInlineBackwardCursor& cursor,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction);
- bool HitTestTextItem(HitTestResult& result,
- const NGFragmentItem& text_item,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction action);
+ const PhysicalOffset& physical_offset);
+ bool HitTestTextItem(const HitTestContext& hit_test,
+ const NGFragmentItem& text_item);
// Hit tests the given line box fragment.
// @param physical_offset Physical offset of the line box fragment in paint
// layer.
- bool HitTestLineBoxFragment(HitTestResult&,
+ bool HitTestLineBoxFragment(const HitTestContext& hit_test,
const NGPhysicalLineBoxFragment& fragment,
const NGInlineBackwardCursor& cursor,
- const HitTestLocation& hit_test_location,
- const PhysicalOffset& physical_offset,
- HitTestAction);
+ const PhysicalOffset& physical_offset);
// Returns whether the hit test location is completely outside the border box,
// which possibly has rounded corners.
@@ -224,6 +275,9 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const HitTestLocation&,
const PhysicalOffset& border_box_location) const;
+ bool HitTestOverflowControl(const HitTestContext&,
+ PhysicalOffset accumulated_offset);
+
const NGPhysicalBoxFragment& PhysicalFragment() const {
return box_fragment_;
}
@@ -231,6 +285,8 @@ class NGBoxFragmentPainter : public BoxPainterBase {
return display_item_client_;
}
const NGBorderEdges& BorderEdges() const;
+ PhysicalRect SelfInkOverflow() const;
+ PhysicalRect ContentsInkOverflow() const;
const NGPhysicalBoxFragment& box_fragment_;
const DisplayItemClient& display_item_client_;
@@ -240,7 +296,7 @@ class NGBoxFragmentPainter : public BoxPainterBase {
const NGPaintFragment* paint_fragment_;
const NGFragmentItems* items_;
const NGFragmentItem* box_item_ = nullptr;
- NGInlineCursor* descendants_ = nullptr;
+ const NGInlineCursor* inline_box_cursor_ = nullptr;
mutable base::Optional<NGBorderEdges> border_edges_;
};
@@ -248,34 +304,45 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPhysicalBoxFragment& box,
const DisplayItemClient& display_item_client,
const NGPaintFragment* paint_fragment,
- NGInlineCursor* descendants)
+ const NGInlineCursor* inline_box_cursor,
+ const NGFragmentItem* box_item)
: BoxPainterBase(&box.GetDocument(), box.Style(), box.GeneratingNode()),
box_fragment_(box),
display_item_client_(display_item_client),
paint_fragment_(paint_fragment),
items_(box.Items()),
- descendants_(descendants) {
+ box_item_(box_item),
+ inline_box_cursor_(inline_box_cursor) {
DCHECK(box.IsBox() || box.IsRenderedLegend());
- DCHECK(!paint_fragment || !descendants);
#if DCHECK_IS_ON()
- if (box.IsInlineBox()) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ DCHECK(!paint_fragment_);
+ if (inline_box_cursor_)
+ DCHECK_EQ(inline_box_cursor_->Current().Item(), box_item_);
+ if (box_item_)
+ DCHECK_EQ(box_item_->BoxFragment(), &box);
+ DCHECK_EQ(box.IsInlineBox(), !!inline_box_cursor_);
+ DCHECK_EQ(box.IsInlineBox(), !!box_item_);
+ } else {
+ DCHECK(!inline_box_cursor_);
+ DCHECK(!box_item_);
if (paint_fragment)
DCHECK_EQ(&paint_fragment->PhysicalFragment(), &box);
- } else if (box.ChildrenInline()) {
- // If no children, there maybe or may not be NGPaintFragment.
- // TODO(kojii): To be investigated if this correct or should be fixed.
- if (!box.Children().empty()) {
- DCHECK(paint_fragment || box.HasItems());
- if (paint_fragment)
- DCHECK_EQ(&paint_fragment->PhysicalFragment(), &box);
+ if (box.IsInlineBox()) {
+ DCHECK(paint_fragment_);
+ } else if (box.IsInlineFormattingContext()) {
+ // If no children, there maybe or may not be NGPaintFragment.
+ // TODO(kojii): To be investigated if this correct or should be fixed.
+ if (!box.Children().empty()) {
+ if (!box.GetLayoutObject() ||
+ !box.GetLayoutObject()->PaintBlockedByDisplayLock(
+ DisplayLockLifecycleTarget::kChildren)) {
+ DCHECK(paint_fragment);
+ }
+ }
+ } else {
+ // We may not have |paint_fragment_| nor |box_item_|.
}
- } else if (box.IsColumnBox() ||
- (box.GetLayoutObject()->SlowFirstChild() &&
- box.GetLayoutObject()->SlowFirstChild()->IsLayoutFlowThread())) {
- // TODO(kojii): NGPaintFragment for multicol has non-inline children
- // (kColumnBox). Could this be regular box fragments?
- } else {
- DCHECK(!paint_fragment);
}
#endif
}
@@ -285,7 +352,8 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
: NGBoxFragmentPainter(fragment,
*fragment.GetLayoutObject(),
/* paint_fragment */ nullptr,
- /* descendants */ nullptr) {}
+ /* inline_box_cursor */ nullptr,
+ /* box_item */ nullptr) {}
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPhysicalBoxFragment& fragment,
@@ -297,7 +365,8 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
: *static_cast<const DisplayItemClient*>(
fragment.GetLayoutObject()),
paint_fragment,
- /* descendants */ nullptr) {}
+ /* inline_box_cursor */ nullptr,
+ /* box_item */ nullptr) {}
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
const NGPaintFragment& paint_fragment)
@@ -307,16 +376,16 @@ inline NGBoxFragmentPainter::NGBoxFragmentPainter(
&paint_fragment) {}
inline NGBoxFragmentPainter::NGBoxFragmentPainter(
+ const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& item,
- const NGPhysicalBoxFragment& fragment,
- NGInlineCursor* descendants)
+ const NGPhysicalBoxFragment& fragment)
: NGBoxFragmentPainter(fragment,
item,
/* paint_fragment */ nullptr,
- descendants) {
+ &inline_box_cursor,
+ &item) {
DCHECK_EQ(item.BoxFragment(), &fragment);
DCHECK(fragment.IsInlineBox());
- box_item_ = &item;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc
index 813071ca277..ccaf7fcbf22 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter_test.cc
@@ -6,6 +6,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -24,10 +25,9 @@ class NGBoxFragmentPainterTest : public PaintControllerPaintTest,
ScopedLayoutNGForTest(true) {}
};
-using NGBoxFragmentPainterScrollHitTestTest = NGBoxFragmentPainterTest;
-INSTANTIATE_SCROLL_HIT_TEST_SUITE_P(NGBoxFragmentPainterScrollHitTestTest);
+INSTANTIATE_PAINT_TEST_SUITE_P(NGBoxFragmentPainterTest);
-TEST_P(NGBoxFragmentPainterScrollHitTestTest, ScrollHitTestOrder) {
+TEST_P(NGBoxFragmentPainterTest, ScrollHitTestOrder) {
GetPage().GetSettings().SetPreferCompositingToLCDTextEnabled(false);
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -43,17 +43,59 @@ TEST_P(NGBoxFragmentPainterScrollHitTestTest, ScrollHitTestOrder) {
</style>
<div id='scroller'>TEXT</div>
)HTML");
- auto& scroller = *GetLayoutObjectByElementId("scroller");
+ auto& scroller = ToLayoutBox(*GetLayoutObjectByElementId("scroller"));
- const NGPaintFragment& root_fragment = *scroller.PaintFragment();
- const NGPaintFragment& line_box_fragment = *root_fragment.FirstChild();
- const NGPaintFragment& text_fragment = *line_box_fragment.FirstChild();
+ const DisplayItemClient& root_fragment =
+ scroller.PaintFragment()
+ ? static_cast<const DisplayItemClient&>(*scroller.PaintFragment())
+ : static_cast<const DisplayItemClient&>(scroller);
+
+ NGInlineCursor cursor;
+ cursor.MoveTo(*scroller.SlowFirstChild());
+ const DisplayItemClient& text_fragment =
+ *cursor.Current().GetDisplayItemClient();
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
DisplayItem::kDocumentBackground),
- IsSameId(&root_fragment, DisplayItem::kScrollHitTest),
IsSameId(&text_fragment, kForegroundType)));
+ HitTestData scroll_hit_test;
+ scroll_hit_test.scroll_translation =
+ &scroller.FirstFragment().ContentsProperties().Transform();
+ scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 40, 40);
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*scroller.Layer(), DisplayItem::kLayerChunk),
+ scroller.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(root_fragment, DisplayItem::kScrollHitTest),
+ scroller.FirstFragment().LocalBorderBoxProperties(),
+ &scroll_hit_test, IntRect(0, 0, 40, 40)),
+ IsPaintChunk(1, 2)));
+ } else {
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(root_fragment, DisplayItem::kScrollHitTest),
+ scroller.FirstFragment().LocalBorderBoxProperties(),
+ &scroll_hit_test, IntRect(0, 0, 40, 40)),
+ IsPaintChunk(1, 2)));
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
index a79eee1c887..fe8baf7fa64 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
@@ -32,11 +32,6 @@ void NGFieldsetPainter::PaintBoxDecorationBackground(
// Paint the fieldset (background, other decorations, and) border, with the
// cutout hole for the legend.
PaintFieldsetDecorationBackground(legend, paint_info, paint_offset);
-
- // Proceed to painting the legend. According to the spec, it should be done as
- // part of the border phase.
- if (legend)
- PaintLegend(To<NGPhysicalBoxFragment>(**legend), paint_info);
}
void NGFieldsetPainter::PaintFieldsetDecorationBackground(
@@ -103,16 +98,4 @@ void NGFieldsetPainter::PaintFieldsetDecorationBackground(
}
}
-void NGFieldsetPainter::PaintLegend(const NGPhysicalBoxFragment& legend,
- const PaintInfo& paint_info) {
- // Unless the legend establishes its own self-painting layer, paint the legend
- // as part of the border phase, according to spec.
- const LayoutObject* legend_object = legend.GetLayoutObject();
- if (ToLayoutBox(legend_object)->HasSelfPaintingLayer())
- return;
- PaintInfo legend_paint_info = paint_info;
- legend_paint_info.phase = PaintPhase::kForeground;
- ObjectPainter(*legend_object).PaintAllPhasesAtomically(legend_paint_info);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h
index ce6012566e4..5a5f601b09d 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h
@@ -27,7 +27,6 @@ class NGFieldsetPainter {
void PaintFieldsetDecorationBackground(const NGLink* legend,
const PaintInfo&,
const PhysicalOffset&);
- void PaintLegend(const NGPhysicalBoxFragment& legend, const PaintInfo&);
const NGPhysicalBoxFragment& fieldset_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
index 3fcbfa66af4..c27547d8ed0 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.cc
@@ -83,23 +83,4 @@ void NGFragmentPainter::AddURLRectIfNeeded(const PaintInfo& paint_info,
paint_info.context.SetURLForRect(url, rect);
}
-bool NGFragmentPainter::ShouldRecordHitTestData(
- const PaintInfo& paint_info,
- const NGPhysicalBoxFragment& fragment) {
- // Hit test display items are only needed for compositing. This flag is used
- // for for printing and drag images which do not need hit testing.
- if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
- return false;
-
- // If an object is not visible, it does not participate in hit testing.
- if (fragment.Style().Visibility() != EVisibility::kVisible)
- return false;
-
- auto touch_action = fragment.EffectiveAllowedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
- return false;
-
- return true;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
index 5d7cee1a9ed..60a21cf012d 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h
@@ -22,28 +22,23 @@ class NGFragmentPainter : public ObjectPainterBase {
public:
NGFragmentPainter(const NGPhysicalBoxFragment& box,
- const NGPaintFragment* paint_fragment)
- : box_fragment_(box), paint_fragment_(paint_fragment) {}
+ const DisplayItemClient& display_item_client)
+ : box_fragment_(box), display_item_client_(display_item_client) {}
void PaintOutline(const PaintInfo&, const PhysicalOffset& paint_offset);
void AddURLRectIfNeeded(const PaintInfo&, const PhysicalOffset& paint_offset);
- static bool ShouldRecordHitTestData(const PaintInfo&,
- const NGPhysicalBoxFragment&);
-
private:
const NGPhysicalBoxFragment& PhysicalFragment() const {
return box_fragment_;
}
const DisplayItemClient& GetDisplayItemClient() const {
- if (paint_fragment_)
- return *paint_fragment_;
- return *PhysicalFragment().GetLayoutObject();
+ return display_item_client_;
}
const NGPhysicalBoxFragment& box_fragment_;
- const NGPaintFragment* paint_fragment_;
+ const DisplayItemClient& display_item_client_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
index dda54a466e9..15aa6b95573 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
@@ -34,7 +34,14 @@ inline bool HasMultiplePaintFragments(const LayoutObject& layout_object) {
}
inline bool HasMultipleFragmentItems(const LayoutObject& layout_object) {
- return HasMultipleItems(NGFragmentItem::ItemsFor(layout_object));
+ NGInlineCursor cursor;
+ cursor.MoveTo(layout_object);
+ DCHECK(cursor);
+ if (cursor) {
+ cursor.MoveToNextForSameLayoutObject();
+ return cursor;
+ }
+ return false;
}
} // namespace
@@ -52,7 +59,7 @@ void NGInlineBoxFragmentPainter::Paint(const PaintInfo& paint_info,
const PhysicalOffset adjusted_paint_offset =
paint_offset + (inline_box_paint_fragment_
? inline_box_paint_fragment_->Offset()
- : inline_box_item_->Offset());
+ : inline_box_item_->OffsetInContainerBlock());
if (paint_info.phase == PaintPhase::kForeground)
PaintBackgroundBorderShadow(paint_info, adjusted_paint_offset);
@@ -64,9 +71,10 @@ void NGInlineBoxFragmentPainter::Paint(const PaintInfo& paint_info,
suppress_box_decoration_background);
return;
}
+ DCHECK(inline_box_cursor_);
DCHECK(inline_box_item_);
- NGBoxFragmentPainter box_painter(*inline_box_item_, PhysicalFragment(),
- descendants_);
+ NGBoxFragmentPainter box_painter(*inline_box_cursor_, *inline_box_item_,
+ PhysicalFragment());
box_painter.PaintObject(paint_info, adjusted_paint_offset,
suppress_box_decoration_background);
}
@@ -112,11 +120,21 @@ void NGInlineBoxFragmentPainterBase::PaintBackgroundBorderShadow(
// TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry.
BackgroundImageGeometry geometry(*static_cast<const LayoutBoxModelObject*>(
inline_box_fragment_.GetLayoutObject()));
- // TODO(kojii): not applicable for line box
- NGBoxFragmentPainter box_painter(
- To<NGPhysicalBoxFragment>(inline_box_fragment_),
- inline_box_paint_fragment_);
const NGBorderEdges& border_edges = BorderEdges();
+ if (inline_box_paint_fragment_) {
+ NGBoxFragmentPainter box_painter(
+ To<NGPhysicalBoxFragment>(inline_box_fragment_),
+ inline_box_paint_fragment_);
+ PaintBoxDecorationBackground(
+ box_painter, paint_info, paint_offset, adjusted_frame_rect, geometry,
+ object_has_multiple_boxes, border_edges.line_left,
+ border_edges.line_right);
+ return;
+ }
+ DCHECK(inline_box_cursor_);
+ NGBoxFragmentPainter box_painter(
+ *inline_box_cursor_, *inline_box_item_,
+ To<NGPhysicalBoxFragment>(inline_box_fragment_));
PaintBoxDecorationBackground(box_painter, paint_info, paint_offset,
adjusted_frame_rect, geometry,
object_has_multiple_boxes,
@@ -178,22 +196,34 @@ void NGInlineBoxFragmentPainterBase::ComputeFragmentOffsetOnLine(
LayoutUnit* offset_on_line,
LayoutUnit* total_width) const {
WritingMode writing_mode = inline_box_fragment_.Style().GetWritingMode();
- NGPaintFragment::FragmentRange fragments =
- inline_box_paint_fragment_->InlineFragmentsFor(
- inline_box_fragment_.GetLayoutObject());
+ NGInlineCursor cursor;
+ DCHECK(inline_box_fragment_.GetLayoutObject());
+ cursor.MoveTo(*inline_box_fragment_.GetLayoutObject());
LayoutUnit before;
LayoutUnit after;
bool before_self = true;
- for (auto iter = fragments.begin(); iter != fragments.end(); ++iter) {
- if (*iter == inline_box_paint_fragment_) {
- before_self = false;
- continue;
+ for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+ if (inline_box_paint_fragment_) {
+ DCHECK(cursor.CurrentPaintFragment());
+ if (cursor.CurrentPaintFragment() == inline_box_paint_fragment_) {
+ before_self = false;
+ continue;
+ }
+ } else {
+ DCHECK(inline_box_item_);
+ DCHECK(cursor.CurrentItem());
+ if (cursor.CurrentItem() == inline_box_item_) {
+ before_self = false;
+ continue;
+ }
}
+ const NGPhysicalBoxFragment* box_fragment = cursor.Current().BoxFragment();
+ DCHECK(box_fragment);
if (before_self)
- before += NGFragment(writing_mode, iter->PhysicalFragment()).InlineSize();
+ before += NGFragment(writing_mode, *box_fragment).InlineSize();
else
- after += NGFragment(writing_mode, iter->PhysicalFragment()).InlineSize();
+ after += NGFragment(writing_mode, *box_fragment).InlineSize();
}
NGFragment logical_fragment(writing_mode, inline_box_fragment_);
@@ -326,7 +356,7 @@ void NGInlineBoxFragmentPainter::PaintAllFragments(
for (const NGPaintFragment* fragment : fragments) {
PhysicalOffset child_offset = paint_offset +
- fragment->InlineOffsetToContainerBox() -
+ fragment->OffsetInContainerBlock() -
fragment->Offset();
DCHECK(fragment->PhysicalFragment().IsBox());
NGInlineBoxFragmentPainter(*fragment).Paint(paint_info, child_offset);
@@ -334,7 +364,6 @@ void NGInlineBoxFragmentPainter::PaintAllFragments(
return;
}
- DCHECK(layout_inline.ShouldCreateBoxFragment());
NGInlineCursor cursor(*block_flow);
cursor.MoveTo(layout_inline);
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
@@ -342,10 +371,23 @@ void NGInlineBoxFragmentPainter::PaintAllFragments(
DCHECK(item);
const NGPhysicalBoxFragment* box_fragment = item->BoxFragment();
DCHECK(box_fragment);
- NGInlineCursor descendants = cursor.CursorForDescendants();
- NGInlineBoxFragmentPainter(*item, *box_fragment, &descendants)
+ NGInlineBoxFragmentPainter(cursor, *item, *box_fragment)
.Paint(paint_info, paint_offset);
}
}
+#if DCHECK_IS_ON()
+void NGInlineBoxFragmentPainter::CheckValid() const {
+ if (inline_box_item_) {
+ DCHECK(inline_box_cursor_);
+ DCHECK_EQ(inline_box_cursor_->Current().Item(), inline_box_item_);
+ }
+
+ DCHECK_EQ(inline_box_fragment_.Type(),
+ NGPhysicalFragment::NGFragmentType::kFragmentBox);
+ DCHECK_EQ(inline_box_fragment_.BoxType(),
+ NGPhysicalFragment::NGBoxType::kInlineBox);
+}
+#endif
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
index 478e697015a..5b2529a74ae 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_INLINE_BOX_FRAGMENT_PAINTER_H_
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/paint/inline_box_painter_base.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
@@ -30,6 +31,7 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
protected:
NGInlineBoxFragmentPainterBase(
const NGPhysicalFragment& inline_box_fragment,
+ const NGInlineCursor* inline_box_cursor,
const NGPaintFragment* inline_box_paint_fragment,
const NGFragmentItem* inline_box_item,
const LayoutObject& layout_object,
@@ -42,8 +44,13 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
line_style),
inline_box_fragment_(inline_box_fragment),
inline_box_paint_fragment_(inline_box_paint_fragment),
- inline_box_item_(inline_box_item) {
+ inline_box_item_(inline_box_item),
+ inline_box_cursor_(inline_box_cursor) {
#if DCHECK_IS_ON()
+ if (inline_box_cursor) {
+ DCHECK(inline_box_item);
+ DCHECK_EQ(inline_box_cursor->Current().Item(), inline_box_item);
+ }
if (inline_box_paint_fragment) {
DCHECK_EQ(&inline_box_paint_fragment->PhysicalFragment(),
&inline_box_fragment);
@@ -65,6 +72,7 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
const ComputedStyle& style,
const ComputedStyle& line_style)
: NGInlineBoxFragmentPainterBase(inline_box_fragment.PhysicalFragment(),
+ /* inline_box_cursor */ nullptr,
&inline_box_fragment,
/* inline_box_item */ nullptr,
layout_object,
@@ -73,12 +81,14 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
// Constructor for |NGFragmentItem|.
NGInlineBoxFragmentPainterBase(
+ const NGInlineCursor& inline_box_cursor,
const NGFragmentItem& inline_box_item,
const NGPhysicalBoxFragment& inline_box_fragment,
const LayoutObject& layout_object,
const ComputedStyle& style,
const ComputedStyle& line_style)
: NGInlineBoxFragmentPainterBase(inline_box_fragment,
+ &inline_box_cursor,
/* inline_box_paint_fragment */ nullptr,
&inline_box_item,
layout_object,
@@ -114,6 +124,7 @@ class NGInlineBoxFragmentPainterBase : public InlineBoxPainterBase {
const NGPhysicalFragment& inline_box_fragment_;
const NGPaintFragment* inline_box_paint_fragment_ = nullptr;
const NGFragmentItem* inline_box_item_ = nullptr;
+ const NGInlineCursor* inline_box_cursor_ = nullptr;
};
// Painter for LayoutNG inline box fragments. Delegates to NGBoxFragmentPainter
@@ -135,19 +146,23 @@ class NGInlineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
}
// Constructor for |NGFragmentItem|.
- NGInlineBoxFragmentPainter(const NGFragmentItem& inline_box_item,
- const NGPhysicalBoxFragment& inline_box_fragment,
- NGInlineCursor* descendants = nullptr)
- : NGInlineBoxFragmentPainterBase(inline_box_item,
+ NGInlineBoxFragmentPainter(const NGInlineCursor& inline_box_cursor,
+ const NGFragmentItem& inline_box_item,
+ const NGPhysicalBoxFragment& inline_box_fragment)
+ : NGInlineBoxFragmentPainterBase(inline_box_cursor,
+ inline_box_item,
inline_box_fragment,
*inline_box_fragment.GetLayoutObject(),
inline_box_fragment.Style(),
- inline_box_fragment.Style()),
- descendants_(descendants) {
- DCHECK_EQ(inline_box_fragment.Type(),
- NGPhysicalFragment::NGFragmentType::kFragmentBox);
- DCHECK_EQ(inline_box_fragment.BoxType(),
- NGPhysicalFragment::NGBoxType::kInlineBox);
+ inline_box_fragment.Style()) {
+ CheckValid();
+ }
+ NGInlineBoxFragmentPainter(const NGInlineCursor& inline_box_cursor,
+ const NGFragmentItem& inline_box_item)
+ : NGInlineBoxFragmentPainter(inline_box_cursor,
+ inline_box_item,
+ *inline_box_item.BoxFragment()) {
+ DCHECK(inline_box_item.BoxFragment());
}
void Paint(const PaintInfo&, const PhysicalOffset& paint_offset);
@@ -163,8 +178,13 @@ class NGInlineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
const NGBorderEdges BorderEdges() const final;
+#if DCHECK_IS_ON()
+ void CheckValid() const;
+#else
+ void CheckValid() const {}
+#endif
+
mutable base::Optional<NGBorderEdges> border_edges_;
- NGInlineCursor* descendants_ = nullptr;
};
// Painter for LayoutNG line box fragments. Line boxes don't paint anything,
@@ -206,6 +226,7 @@ class NGLineBoxFragmentPainter : public NGInlineBoxFragmentPainterBase {
const LayoutObject& layout_block_flow)
: NGInlineBoxFragmentPainterBase(
line_box_fragment,
+ /* inline_box_cursor */ nullptr,
line_box_paint_fragment,
line_box_item,
layout_block_flow,
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
new file mode 100644
index 00000000000..68e778f333d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h"
+
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
+#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
+#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+
+namespace blink {
+
+void NGMathMLPainter::PaintBar(const PaintInfo& info, const IntRect& bar) {
+ if (bar.IsEmpty())
+ return;
+
+ GraphicsContextStateSaver state_saver(info.context);
+ info.context.SetStrokeThickness(bar.Height());
+ info.context.SetStrokeStyle(kSolidStroke);
+ info.context.SetStrokeColor(
+ box_fragment_.Style().VisitedDependentColor(GetCSSPropertyColor()));
+ IntPoint line_end_point = {bar.Width(), 0};
+ info.context.DrawLine(bar.Location(), bar.Location() + line_end_point);
+}
+
+void NGMathMLPainter::PaintFractionBar(const PaintInfo& info,
+ PhysicalOffset paint_offset) {
+ const DisplayItemClient& display_item_client =
+ *box_fragment_.GetLayoutObject();
+ if (DrawingRecorder::UseCachedDrawingIfPossible(
+ info.context, display_item_client, info.phase))
+ return;
+
+ DrawingRecorder recorder(info.context, display_item_client, info.phase);
+
+ DCHECK(box_fragment_.Style().IsHorizontalWritingMode());
+ const ComputedStyle& style = box_fragment_.Style();
+ LayoutUnit line_thickness = FractionLineThickness(style);
+ if (!line_thickness)
+ return;
+ LayoutUnit axis_height = MathAxisHeight(style);
+ if (auto baseline = box_fragment_.Baseline()) {
+ auto borders = box_fragment_.Borders();
+ auto padding = box_fragment_.Padding();
+ PhysicalRect bar_rect = {
+ borders.left + padding.left, *baseline - axis_height,
+ box_fragment_.Size().width - borders.HorizontalSum() -
+ padding.HorizontalSum(),
+ line_thickness};
+ bar_rect.Move(paint_offset);
+ PaintBar(info, PixelSnappedIntRect(bar_rect));
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h
new file mode 100644
index 00000000000..70233e8017f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_mathml_painter.h
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_MATHML_PAINTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_MATHML_PAINTER_H_
+
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
+namespace blink {
+
+struct PaintInfo;
+struct PhysicalOffset;
+class IntRect;
+class NGPhysicalBoxFragment;
+
+class NGMathMLPainter {
+ STACK_ALLOCATED();
+
+ public:
+ explicit NGMathMLPainter(const NGPhysicalBoxFragment& box_fragment)
+ : box_fragment_(box_fragment) {}
+ void PaintFractionBar(const PaintInfo&, PhysicalOffset);
+
+ private:
+ void PaintBar(const PaintInfo&, const IntRect&);
+
+ const NGPhysicalBoxFragment& box_fragment_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_MATHML_PAINTER_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 8d5848d2cd6..9cd79dd07b2 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -21,7 +21,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
@@ -116,7 +115,7 @@ LogicalRect ExpandedSelectionRectForSoftLineBreakIfNeeded(
if (layout_block_flow && layout_block_flow->ShouldTruncateOverflowingText())
return rect;
// Copy from InlineTextBoxPainter::PaintSelection.
- const LayoutUnit space_width(cursor.CurrentStyle().GetFont().SpaceWidth());
+ const LayoutUnit space_width(cursor.Current().Style().GetFont().SpaceWidth());
return {rect.offset,
{rect.size.inline_size + space_width, rect.size.block_size}};
}
@@ -139,7 +138,9 @@ LogicalRect ExpandSelectionRectToLineHeight(const LogicalRect& rect,
NGInlineCursor line(cursor);
line.MoveToContainingLine();
const PhysicalRect line_physical_rect(
- line.CurrentOffset() - cursor.CurrentOffset(), line.CurrentSize());
+ line.Current().OffsetInContainerBlock() -
+ cursor.Current().OffsetInContainerBlock(),
+ line.Current().Size());
return ExpandSelectionRectToLineHeight(
rect, ComputeLogicalRectFor(line_physical_rect, cursor));
}
@@ -432,8 +433,8 @@ void NGPaintFragment::PopulateDescendants(CreateContext* parent_context) {
scoped_refptr<NGPaintFragment>* last_child_ptr = &first_child_;
auto* box_physical_fragment = DynamicTo<NGPhysicalBoxFragment>(fragment);
- bool children_are_inline =
- !box_physical_fragment || box_physical_fragment->ChildrenInline();
+ bool is_inline_fc = !box_physical_fragment ||
+ box_physical_fragment->IsInlineFormattingContext();
for (const NGLink& child_fragment : container.Children()) {
child_fragment->CheckType();
@@ -444,11 +445,11 @@ void NGPaintFragment::PopulateDescendants(CreateContext* parent_context) {
child_context.populate_children =
child_fragment->IsContainer() &&
- !child_fragment->IsBlockFormattingContextRoot();
+ !child_fragment->IsFormattingContextRoot();
scoped_refptr<NGPaintFragment> child = CreateOrReuse(
child_fragment.get(), child_fragment.Offset(), &child_context);
- if (children_are_inline) {
+ if (is_inline_fc) {
DCHECK(!child_fragment->IsOutOfFlowPositioned());
if (child_fragment->IsText() || child_fragment->IsInlineBox() ||
child_fragment->IsAtomicInline()) {
@@ -506,12 +507,15 @@ void NGPaintFragment::AssociateWithLayoutObject(
return;
}
// This |layout_object| was fragmented across multiple blocks.
+ DCHECK_EQ(layout_object, first_fragment->GetLayoutObject());
NGPaintFragment* last_fragment = first_fragment->LastForSameLayoutObject();
last_fragment->next_for_same_layout_object_ = this;
return;
}
- DCHECK(add_result.stored_value->value);
- add_result.stored_value->value->next_for_same_layout_object_ = this;
+ NGPaintFragment* last_fragment = add_result.stored_value->value;
+ DCHECK(last_fragment) << layout_object;
+ DCHECK_EQ(layout_object, last_fragment->GetLayoutObject());
+ last_fragment->next_for_same_layout_object_ = this;
add_result.stored_value->value = this;
}
@@ -537,7 +541,7 @@ void NGPaintFragment::ClearAssociationWithLayoutObject() {
fragment.IsColumnBox()) {
child->ClearAssociationWithLayoutObject();
} else {
- DCHECK(fragment.IsText() || fragment.IsBlockFormattingContextRoot());
+ DCHECK(fragment.IsText() || fragment.IsFormattingContextRoot());
DCHECK(child->Children().IsEmpty());
}
}
@@ -640,7 +644,7 @@ PhysicalRect NGPaintFragment::RecalcContentsInkOverflow() const {
// A BFC root establishes a separate NGPaintFragment tree. Re-compute the
// child tree using its LayoutObject, because it may not be NG.
- if (child_fragment.IsBlockFormattingContextRoot()) {
+ if (child_fragment.IsFormattingContextRoot()) {
LayoutBox* layout_box =
ToLayoutBox(child_fragment.GetMutableLayoutObject());
layout_box->RecalcVisualOverflow();
@@ -661,7 +665,7 @@ PhysicalRect NGPaintFragment::RecalcContentsInkOverflow() const {
PhysicalRect NGPaintFragment::RecalcInkOverflow() {
const NGPhysicalFragment& fragment = PhysicalFragment();
fragment.CheckCanUpdateInkOverflow();
- DCHECK(!fragment.IsBlockFormattingContextRoot());
+ DCHECK(!fragment.IsFormattingContextRoot());
// NGPhysicalTextFragment caches ink overflow in layout. No need to recalc nor
// to store in NGPaintFragment.
@@ -755,7 +759,7 @@ base::Optional<PhysicalRect> NGPaintFragment::LocalVisualRectFor(
if (fragment->PhysicalFragment().IsHiddenForPaint())
continue;
PhysicalRect child_visual_rect = fragment->SelfInkOverflow();
- child_visual_rect.offset += fragment->InlineOffsetToContainerBox();
+ child_visual_rect.offset += fragment->OffsetInContainerBlock();
visual_rect.Unite(child_visual_rect);
}
return visual_rect;
@@ -781,7 +785,9 @@ NGPaintFragment* NGPaintFragment::FirstLineBox() const {
}
const NGPaintFragment* NGPaintFragment::Root() const {
- DCHECK(PhysicalFragment().IsInline());
+ // Because of this function can be called during |LayoutObject::Destroy()|,
+ // we use |physical_fragment_| to avoid calling |IsAlive()|.
+ DCHECK(physical_fragment_->IsInline());
const NGPaintFragment* root = this;
for (const NGPaintFragment* fragment :
NGPaintFragmentTraversal::InclusiveAncestorsOf(*this)) {
@@ -915,17 +921,19 @@ PhysicalRect ComputeLocalSelectionRectForText(
LogicalRect logical_rect = ComputeLogicalRectFor(selection_rect, cursor);
// Let LocalRect for line break have a space width to paint line break
// when it is only character in a line or only selected in a line.
- if (selection_status.start != selection_status.end && cursor.IsLineBreak() &&
+ if (selection_status.start != selection_status.end &&
+ cursor.Current().IsLineBreak() &&
// This is for old compatible that old doesn't paint last br in a page.
- !IsLastBRInPage(*cursor.CurrentLayoutObject())) {
+ !IsLastBRInPage(*cursor.Current().GetLayoutObject())) {
DCHECK(!logical_rect.size.inline_size);
logical_rect.size.inline_size =
- LayoutUnit(cursor.CurrentStyle().GetFont().SpaceWidth());
+ LayoutUnit(cursor.Current().Style().GetFont().SpaceWidth());
}
const LogicalRect line_break_extended_rect =
- cursor.IsLineBreak() ? logical_rect
- : ExpandedSelectionRectForSoftLineBreakIfNeeded(
- logical_rect, cursor, selection_status);
+ cursor.Current().IsLineBreak()
+ ? logical_rect
+ : ExpandedSelectionRectForSoftLineBreakIfNeeded(logical_rect, cursor,
+ selection_status);
const LogicalRect line_height_expanded_rect =
ExpandSelectionRectToLineHeight(line_break_extended_rect, cursor);
const PhysicalRect physical_rect =
@@ -937,8 +945,8 @@ PhysicalRect ComputeLocalSelectionRectForText(
// "ng_selection_painter.cc".
PhysicalRect ComputeLocalSelectionRectForReplaced(
const NGInlineCursor& cursor) {
- DCHECK(cursor.CurrentLayoutObject()->IsLayoutReplaced());
- const PhysicalRect selection_rect = PhysicalRect({}, cursor.CurrentSize());
+ DCHECK(cursor.Current().GetLayoutObject()->IsLayoutReplaced());
+ const PhysicalRect selection_rect = PhysicalRect({}, cursor.Current().Size());
LogicalRect logical_rect = ComputeLogicalRectFor(selection_rect, cursor);
const LogicalRect line_height_expanded_rect =
ExpandSelectionRectToLineHeight(logical_rect, cursor);
@@ -1038,7 +1046,9 @@ PositionWithAffinity NGPaintFragment::PositionForPointInInlineFormattingContext(
const PhysicalOffset& point) const {
DCHECK(PhysicalFragment().IsBlockFlow());
DCHECK(PhysicalFragment().IsBox());
- DCHECK(To<NGPhysicalBoxFragment>(PhysicalFragment()).ChildrenInline());
+ DCHECK(To<NGPhysicalBoxFragment>(PhysicalFragment())
+ .GetLayoutObject()
+ ->ChildrenInline());
const LogicalOffset logical_point = point.ConvertToLogical(
Style().GetWritingMode(), Style().Direction(), Size(),
@@ -1117,7 +1127,6 @@ PositionWithAffinity NGPaintFragment::PositionForPoint(
// We current fall back to legacy for block formatting contexts, so we
// should reach here only for inline formatting contexts.
// TODO(xiaochengh): Do not fall back.
- DCHECK(To<NGPhysicalBoxFragment>(PhysicalFragment()).ChildrenInline());
return PositionForPointInInlineFormattingContext(point);
}
@@ -1131,13 +1140,16 @@ String NGPaintFragment::DebugName() const {
DCHECK(physical_fragment_);
const NGPhysicalFragment& physical_fragment = *physical_fragment_;
if (physical_fragment.IsBox()) {
+ const LayoutObject* layout_object = physical_fragment.GetLayoutObject();
+ if (!layout_object)
+ return "NGPhysicalBoxFragment";
+ // For the root |NGPaintFragment|, return the name of the |LayoutObject| to
+ // ease the transition to |NGFragmentItem|.
+ if (!Parent())
+ return layout_object->DebugName();
name.Append("NGPhysicalBoxFragment");
- if (const LayoutObject* layout_object =
- physical_fragment.GetLayoutObject()) {
- DCHECK(physical_fragment.IsBox());
- name.Append(' ');
- name.Append(layout_object->DebugName());
- }
+ name.Append(' ');
+ name.Append(layout_object->DebugName());
} else if (physical_fragment.IsText()) {
name.Append("NGPhysicalTextFragment '");
name.Append(To<NGPhysicalTextFragment>(physical_fragment).Text());
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index 6ec7dadfd82..fd197b7cd86 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -155,10 +155,13 @@ class CORE_EXPORT NGPaintFragment : public RefCounted<NGPaintFragment>,
bool IsDirty() const { return is_dirty_inline_; }
// Returns offset to its container box for inline and line box fragments.
- const PhysicalOffset& InlineOffsetToContainerBox() const {
+ const PhysicalOffset& OffsetInContainerBlock() const {
DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox());
return inline_offset_to_container_box_;
}
+ const PhysicalRect RectInContainerBlock() const {
+ return PhysicalRect(OffsetInContainerBlock(), Size());
+ }
// InkOverflow of itself, not including contents, in the local coordinate.
PhysicalRect SelfInkOverflow() const;
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
index c301ed5cc5c..d778705c23d 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
@@ -45,6 +45,8 @@ class NGPaintFragmentTest : public RenderingTest,
};
TEST_F(NGPaintFragmentTest, InlineFragmentsFor) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -70,7 +72,7 @@ TEST_F(NGPaintFragmentTest, InlineFragmentsFor) {
results.AppendRange(it.begin(), it.end());
EXPECT_EQ(1u, results.size());
EXPECT_EQ(text1, results[0]->GetLayoutObject());
- EXPECT_EQ(PhysicalOffset(), results[0]->InlineOffsetToContainerBox());
+ EXPECT_EQ(PhysicalOffset(), results[0]->OffsetInContainerBlock());
results.clear();
it = NGPaintFragment::InlineFragmentsFor(box);
@@ -80,15 +82,15 @@ TEST_F(NGPaintFragmentTest, InlineFragmentsFor) {
EXPECT_EQ(box, results[1]->GetLayoutObject());
EXPECT_EQ(box, results[2]->GetLayoutObject());
- EXPECT_EQ(PhysicalOffset(60, 0), results[0]->InlineOffsetToContainerBox());
+ EXPECT_EQ(PhysicalOffset(60, 0), results[0]->OffsetInContainerBlock());
EXPECT_EQ("789", To<NGPhysicalTextFragment>(
results[0]->FirstChild()->PhysicalFragment())
.Text());
- EXPECT_EQ(PhysicalOffset(0, 10), results[1]->InlineOffsetToContainerBox());
+ EXPECT_EQ(PhysicalOffset(0, 10), results[1]->OffsetInContainerBlock());
EXPECT_EQ("123456789", To<NGPhysicalTextFragment>(
results[1]->FirstChild()->PhysicalFragment())
.Text());
- EXPECT_EQ(PhysicalOffset(0, 20), results[2]->InlineOffsetToContainerBox());
+ EXPECT_EQ(PhysicalOffset(0, 20), results[2]->OffsetInContainerBlock());
EXPECT_EQ("123", To<NGPhysicalTextFragment>(
results[2]->FirstChild()->PhysicalFragment())
.Text());
@@ -102,6 +104,8 @@ TEST_F(NGPaintFragmentTest, InlineFragmentsFor) {
} while (false)
TEST_F(NGPaintFragmentTest, InlineBox) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -145,6 +149,8 @@ TEST_F(NGPaintFragmentTest, InlineBox) {
}
TEST_F(NGPaintFragmentTest, InlineBoxVerticalRL) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -189,6 +195,8 @@ TEST_F(NGPaintFragmentTest, InlineBoxVerticalRL) {
}
TEST_F(NGPaintFragmentTest, InlineBoxWithDecorations) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -244,6 +252,8 @@ TEST_F(NGPaintFragmentTest, InlineBoxWithDecorations) {
}
TEST_F(NGPaintFragmentTest, InlineBoxWithDecorationsVerticalRL) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -300,6 +310,8 @@ TEST_F(NGPaintFragmentTest, InlineBoxWithDecorationsVerticalRL) {
}
TEST_F(NGPaintFragmentTest, InlineBlock) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -404,6 +416,8 @@ TEST_F(NGPaintFragmentTest, InlineBlock) {
}
TEST_F(NGPaintFragmentTest, InlineBlockVerticalRL) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -511,6 +525,8 @@ TEST_F(NGPaintFragmentTest, InlineBlockVerticalRL) {
}
TEST_F(NGPaintFragmentTest, RelativeBlock) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -550,6 +566,8 @@ TEST_F(NGPaintFragmentTest, RelativeBlock) {
}
TEST_F(NGPaintFragmentTest, RelativeInline) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -604,6 +622,8 @@ TEST_F(NGPaintFragmentTest, RelativeInline) {
}
TEST_F(NGPaintFragmentTest, RelativeBlockAndInline) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
@@ -659,6 +679,8 @@ TEST_F(NGPaintFragmentTest, RelativeBlockAndInline) {
// Test that OOF should not create a NGPaintFragment.
TEST_F(NGPaintFragmentTest, OutOfFlow) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML(R"HTML(
<!DOCTYPE html>
<style>
@@ -683,6 +705,8 @@ TEST_F(NGPaintFragmentTest, OutOfFlow) {
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveBr) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -710,6 +734,8 @@ INSTANTIATE_TEST_SUITE_P(NGPaintFragmentTest,
testing::ValuesIn(inline_child_data));
TEST_P(InlineChildTest, RemoveInlineChild) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML(String(R"HTML(
<!DOCTYPE html>
<style>
@@ -735,6 +761,8 @@ TEST_P(InlineChildTest, RemoveInlineChild) {
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveChild) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -750,6 +778,8 @@ TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveChild) {
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveSpanWithBr) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -768,6 +798,8 @@ TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveSpanWithBr) {
// to update |IsDirty|, but NGPaintFragment maybe re-used during the layout. In
// such case, the result is not deterministic.
TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtStart) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -785,7 +817,7 @@ TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtStart) {
Element& target = *GetDocument().getElementById("target");
target.parentNode()->insertBefore(Text::Create(GetDocument(), "XYZ"),
&target);
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
EXPECT_TRUE(line1->IsDirty());
EXPECT_FALSE(line2->IsDirty());
@@ -796,6 +828,8 @@ TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtStart) {
// to update |IsDirty|, but NGPaintFragment maybe re-used during the layout. In
// such case, the result is not deterministic.
TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtLast) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -812,7 +846,7 @@ TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtLast) {
ASSERT_TRUE(line3->PhysicalFragment().IsLineBox()) << line3;
Element& target = *GetDocument().getElementById("target");
target.parentNode()->appendChild(Text::Create(GetDocument(), "XYZ"));
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
EXPECT_FALSE(line1->IsDirty());
EXPECT_FALSE(line2->IsDirty());
@@ -823,6 +857,8 @@ TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtLast) {
// to update |IsDirty|, but NGPaintFragment maybe re-used during the layout. In
// such case, the result is not deterministic.
TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtMiddle) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -840,7 +876,7 @@ TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtMiddle) {
Element& target = *GetDocument().getElementById("target");
target.parentNode()->insertBefore(Text::Create(GetDocument(), "XYZ"),
target.nextSibling());
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
EXPECT_TRUE(line1->IsDirty());
EXPECT_FALSE(line2->IsDirty());
@@ -848,6 +884,8 @@ TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtMiddle) {
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByTextSetData) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(
@@ -863,6 +901,8 @@ TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByTextSetData) {
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyWrappedLine) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(R"HTML(
@@ -887,6 +927,8 @@ TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyWrappedLine) {
}
TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyInsideInlineBlock) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled())
return;
SetBodyInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
index 9714f1cc1cc..e5c4b783bc7 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
@@ -272,7 +272,7 @@ bool NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::
bool NGPaintFragmentTraversal::InlineDescendantsRange::Iterator::ShouldTraverse(
const NGPaintFragment& fragment) {
return fragment.PhysicalFragment().IsContainer() &&
- !fragment.PhysicalFragment().IsBlockFormattingContextRoot();
+ !fragment.PhysicalFragment().IsFormattingContextRoot();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc
index e4e8110f82c..78d645533bf 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal_test.cc
@@ -63,6 +63,8 @@ class NGPaintFragmentTraversalTest : public RenderingTest,
};
TEST_F(NGPaintFragmentTraversalTest, MoveToNext) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t", R"HTML(
<div id=t>
line0
@@ -83,6 +85,8 @@ TEST_F(NGPaintFragmentTraversalTest, MoveToNext) {
}
TEST_F(NGPaintFragmentTraversalTest, MoveToNextWithRoot) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t", R"HTML(
<div id=t>
line0
@@ -101,6 +105,8 @@ TEST_F(NGPaintFragmentTraversalTest, MoveToNextWithRoot) {
}
TEST_F(NGPaintFragmentTraversalTest, MoveToPrevious) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t", R"HTML(
<div id=t>
line0
@@ -122,6 +128,8 @@ TEST_F(NGPaintFragmentTraversalTest, MoveToPrevious) {
}
TEST_F(NGPaintFragmentTraversalTest, MoveToPreviousWithRoot) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t", R"HTML(
<div id=t>
line0
@@ -141,6 +149,8 @@ TEST_F(NGPaintFragmentTraversalTest, MoveToPreviousWithRoot) {
}
TEST_F(NGPaintFragmentTraversalTest, MoveTo) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t", R"HTML(
<div id=t>
line0
@@ -162,6 +172,8 @@ TEST_F(NGPaintFragmentTraversalTest, MoveTo) {
}
TEST_F(NGPaintFragmentTraversalTest, MoveToWithRoot) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t", R"HTML(
<div id=t>
line0
@@ -181,6 +193,8 @@ TEST_F(NGPaintFragmentTraversalTest, MoveToWithRoot) {
}
TEST_F(NGPaintFragmentTraversalTest, InlineDescendantsOf) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetUpHtml("t",
"<ul>"
"<li id=t style='position: absolute'>"
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 4ecd342ed01..23d62f21cb8 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -64,6 +64,49 @@ inline const NGPaintFragment& AsDisplayItemClient(
return cursor.PaintFragment();
}
+inline PhysicalRect ComputeBoxRect(const NGInlineCursor& cursor,
+ const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset) {
+ PhysicalRect box_rect = cursor.CurrentItem()->RectInContainerBlock();
+ box_rect.offset.left += paint_offset.left;
+ // We round the y-axis to ensure consistent line heights.
+ box_rect.offset.top =
+ LayoutUnit((paint_offset.top + parent_offset.top).Round()) +
+ (box_rect.offset.top - parent_offset.top);
+ return box_rect;
+}
+
+inline PhysicalRect ComputeBoxRect(const NGTextPainterCursor& cursor,
+ const PhysicalOffset& paint_offset,
+ const PhysicalOffset& parent_offset) {
+ PhysicalRect box_rect = cursor.PaintFragment().Rect();
+ // We round the y-axis to ensure consistent line heights.
+ PhysicalOffset adjusted_paint_offset(paint_offset.left,
+ LayoutUnit(paint_offset.top.Round()));
+ box_rect.offset += adjusted_paint_offset;
+ return box_rect;
+}
+
+inline const NGInlineCursor& InlineCursorForBlockFlow(
+ const NGInlineCursor& cursor,
+ base::Optional<NGInlineCursor>* storage) {
+ if (*storage)
+ return **storage;
+ *storage = cursor;
+ (*storage)->ExpandRootToContainingBlock();
+ return **storage;
+}
+
+inline const NGInlineCursor& InlineCursorForBlockFlow(
+ const NGTextPainterCursor& cursor,
+ base::Optional<NGInlineCursor>* storage) {
+ if (*storage)
+ return **storage;
+ storage->emplace(cursor.RootPaintFragment());
+ (*storage)->MoveTo(cursor.PaintFragment());
+ return **storage;
+}
+
// TODO(yosin): Remove |GetTextFragmentPaintInfo| once the transition to
// |NGFragmentItem| is done. http://crbug.com/982194
inline NGTextFragmentPaintInfo GetTextFragmentPaintInfo(
@@ -98,28 +141,14 @@ inline std::pair<LayoutUnit, LayoutUnit> GetLineLeftAndRightForOffsets(
// |NGFragmentItem| is done. http://crbug.com/982194
inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
const NGInlineCursor& cursor) {
- return cursor.CurrentItem()
- ->GetLayoutObject()
+ return cursor.Current()
+ .GetLayoutObject()
->GetDocument()
.GetFrame()
->Selection()
.ComputeLayoutSelectionStatus(cursor);
}
-inline LayoutSelectionStatus ComputeLayoutSelectionStatus(
- const NGTextPainterCursor& cursor) {
- // Note:: Because of this function is hot, we should not use |NGInlineCursor|
- // on paint fragment which requires traversing ancestors to root.
- NGInlineCursor inline_cursor(cursor.RootPaintFragment());
- inline_cursor.MoveTo(cursor.PaintFragment());
- return cursor.CurrentItem()
- ->GetLayoutObject()
- ->GetDocument()
- .GetFrame()
- ->Selection()
- .ComputeLayoutSelectionStatus(inline_cursor);
-}
-
// TODO(yosin): Remove |ComputeLocalRect| once the transition to
// |NGFragmentItem| is done. http://crbug.com/982194
inline PhysicalRect ComputeLocalRect(const NGFragmentItem& text_item,
@@ -181,19 +210,24 @@ unsigned ClampOffset(unsigned offset, const TextItem& text_fragment) {
}
void PaintRect(GraphicsContext& context,
- const PhysicalOffset& location,
const PhysicalRect& rect,
const Color color) {
if (!color.Alpha())
return;
if (rect.size.IsEmpty())
return;
- const IntRect pixel_snapped_rect =
- PixelSnappedIntRect(PhysicalRect(rect.offset + location, rect.size));
+ const IntRect pixel_snapped_rect = PixelSnappedIntRect(rect);
if (!pixel_snapped_rect.IsEmpty())
context.FillRect(pixel_snapped_rect, color);
}
+void PaintRect(GraphicsContext& context,
+ const PhysicalOffset& location,
+ const PhysicalRect& rect,
+ const Color color) {
+ PaintRect(context, PhysicalRect(rect.offset + location, rect.size), color);
+}
+
template <typename TextItem>
PhysicalRect MarkerRectForForeground(const TextItem& text_fragment,
StringView text,
@@ -310,6 +344,92 @@ void PaintDocumentMarkers(GraphicsContext& context,
}
}
+class SelectionPaintState {
+ STACK_ALLOCATED();
+
+ public:
+ explicit SelectionPaintState(const NGInlineCursor& containing_block)
+ : selection_status_(ComputeLayoutSelectionStatus(containing_block)),
+ containing_block_(containing_block) {}
+
+ const LayoutSelectionStatus& Status() const { return selection_status_; }
+
+ bool ShouldPaintSelectedTextOnly() const { return paint_selected_text_only_; }
+
+ bool ShouldPaintSelectedTextSeparately() const {
+ return paint_selected_text_separately_;
+ }
+
+ bool IsSelectionRectComputed() const { return selection_rect_.has_value(); }
+
+ void ComputeSelectionStyle(const Document& document,
+ const ComputedStyle& style,
+ Node* node,
+ const PaintInfo& paint_info,
+ const TextPaintStyle& text_style) {
+ selection_style_ = TextPainterBase::SelectionPaintingStyle(
+ document, style, node, /*have_selection*/ true, paint_info, text_style);
+ paint_selected_text_only_ =
+ (paint_info.phase == PaintPhase::kSelectionDragImage);
+ paint_selected_text_separately_ =
+ !paint_selected_text_only_ && text_style != selection_style_;
+ }
+
+ void ComputeSelectionRect(const PhysicalOffset& box_offset) {
+ DCHECK(!selection_rect_);
+ selection_rect_ =
+ ComputeLocalSelectionRectForText(containing_block_, selection_status_);
+ selection_rect_->offset += box_offset;
+ }
+
+ // Logic is copied from InlineTextBoxPainter::PaintSelection.
+ // |selection_start| and |selection_end| should be between
+ // [text_fragment.StartOffset(), text_fragment.EndOffset()].
+ void PaintSelectionBackground(GraphicsContext& context,
+ Node* node,
+ const Document& document,
+ const ComputedStyle& style) {
+ const Color color = SelectionBackgroundColor(document, style, node,
+ selection_style_.fill_color);
+ PaintRect(context, *selection_rect_, color);
+ }
+
+ // Paint the selected text only.
+ void PaintSelectedText(NGTextPainter& text_painter,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ DOMNodeId node_id) {
+ text_painter.PaintSelectedText(selection_status_.start,
+ selection_status_.end, length, text_style,
+ selection_style_, *selection_rect_, node_id);
+ }
+
+ // Paint the text except selected parts. Does nothing if all is selected.
+ void PaintBeforeAndAfterSelectedText(NGTextPainter& text_painter,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ DOMNodeId node_id) {
+ if (start_offset < selection_status_.start) {
+ text_painter.Paint(start_offset, selection_status_.start, length,
+ text_style, node_id);
+ }
+ if (selection_status_.end < end_offset) {
+ text_painter.Paint(selection_status_.end, end_offset, length, text_style,
+ node_id);
+ }
+ }
+
+ private:
+ LayoutSelectionStatus selection_status_;
+ TextPaintStyle selection_style_;
+ base::Optional<PhysicalRect> selection_rect_;
+ const NGInlineCursor& containing_block_;
+ bool paint_selected_text_only_;
+ bool paint_selected_text_separately_;
+};
+
} // namespace
StringView NGTextPainterCursor::CurrentText() const {
@@ -323,37 +443,6 @@ const NGPaintFragment& NGTextPainterCursor::RootPaintFragment() const {
}
template <typename Cursor>
-NGTextFragmentPainter<Cursor>::NGTextFragmentPainter(const Cursor& cursor)
- : cursor_(cursor) {}
-
-static PhysicalRect ComputeLocalSelectionRectForText(
- const NGTextPainterCursor& cursor,
- const LayoutSelectionStatus& selection_status) {
- NGInlineCursor inline_cursor(cursor.RootPaintFragment());
- inline_cursor.MoveTo(cursor.PaintFragment());
- return ComputeLocalSelectionRectForText(inline_cursor, selection_status);
-}
-
-// Logic is copied from InlineTextBoxPainter::PaintSelection.
-// |selection_start| and |selection_end| should be between
-// [text_fragment.StartOffset(), text_fragment.EndOffset()].
-template <typename Cursor>
-static void PaintSelection(GraphicsContext& context,
- const Cursor& cursor,
- Node* node,
- const Document& document,
- const ComputedStyle& style,
- Color text_color,
- const PhysicalRect& box_rect,
- const LayoutSelectionStatus& selection_status) {
- const Color color =
- SelectionBackgroundColor(document, style, node, text_color);
- const PhysicalRect selection_rect =
- ComputeLocalSelectionRectForText(cursor, selection_status);
- PaintRect(context, box_rect.offset, selection_rect, color);
-}
-
-template <typename Cursor>
void NGTextFragmentPainter<Cursor>::PaintSymbol(
const LayoutObject* layout_object,
const ComputedStyle& style,
@@ -390,23 +479,23 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
GetTextFragmentPaintInfo(cursor_);
const LayoutObject* layout_object = text_item.GetLayoutObject();
const ComputedStyle& style = text_item.Style();
- PhysicalRect box_rect = AsDisplayItemClient(cursor_).Rect();
const Document& document = layout_object->GetDocument();
const bool is_printing = paint_info.IsPrinting();
// Determine whether or not we're selected.
- bool have_selection = !is_printing &&
- paint_info.phase != PaintPhase::kTextClip &&
- layout_object->IsSelected();
- base::Optional<LayoutSelectionStatus> selection_status;
- if (have_selection) {
- selection_status = ComputeLayoutSelectionStatus(cursor_);
- DCHECK_LE(selection_status->start, selection_status->end);
- have_selection = selection_status->start < selection_status->end;
+ base::Optional<SelectionPaintState> selection;
+ if (UNLIKELY(!is_printing && paint_info.phase != PaintPhase::kTextClip &&
+ layout_object->IsSelected())) {
+ const NGInlineCursor& root_inline_cursor =
+ InlineCursorForBlockFlow(cursor_, &inline_cursor_for_block_flow_);
+ selection.emplace(root_inline_cursor);
+ if (!selection->Status().HasValidRange())
+ selection.reset();
}
- if (!have_selection) {
- // When only painting the selection, don't bother to paint if there is none.
- if (paint_info.phase == PaintPhase::kSelection)
+ if (!selection) {
+ // When only painting the selection drag image, don't bother to paint if
+ // there is none.
+ if (paint_info.phase == PaintPhase::kSelectionDragImage)
return;
// Flow controls (line break, tab, <wbr>) need only selection painting.
@@ -426,6 +515,8 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
paint_info.phase);
}
+ PhysicalRect box_rect = ComputeBoxRect(cursor_, paint_offset, parent_offset_);
+
if (UNLIKELY(text_item.IsSymbolMarker())) {
// The NGInlineItem of marker might be Split(). To avoid calling PaintSymbol
// multiple times, only call it the first time. For an outside marker, this
@@ -438,15 +529,10 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
return;
}
PaintSymbol(layout_object, style, box_rect.size, paint_info,
- paint_offset + box_rect.offset);
+ box_rect.offset);
return;
}
- // We round the y-axis to ensure consistent line heights.
- PhysicalOffset adjusted_paint_offset(paint_offset.left,
- LayoutUnit(paint_offset.top.Round()));
- box_rect.offset += adjusted_paint_offset;
-
GraphicsContext& context = paint_info.context;
// Determine text colors.
@@ -454,11 +540,10 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
Node* node = layout_object->GetNode();
TextPaintStyle text_style =
TextPainterBase::TextPaintingStyle(document, style, paint_info);
- TextPaintStyle selection_style = TextPainterBase::SelectionPaintingStyle(
- document, style, node, have_selection, paint_info, text_style);
- bool paint_selected_text_only = (paint_info.phase == PaintPhase::kSelection);
- bool paint_selected_text_separately =
- !paint_selected_text_only && text_style != selection_style;
+ if (UNLIKELY(selection)) {
+ selection->ComputeSelectionStyle(document, style, node, paint_info,
+ text_style);
+ }
// Set our font.
const Font& font = style.GetFont();
@@ -474,17 +559,17 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
// before GraphicsContext flip.
// TODO(yoichio): Make NGPhysicalTextFragment::LocalRect and
// NGPaintFragment::ComputeLocalSelectionRectForText logical so that we can
- // paint selection in same fliped dimention as NGTextPainter.
+ // paint selection in same flipped dimension as NGTextPainter.
const DocumentMarkerVector& markers_to_paint =
ComputeMarkersToPaint(node, text_item.IsEllipsis());
- if (paint_info.phase != PaintPhase::kSelection &&
+ if (paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kTextClip && !is_printing) {
PaintDocumentMarkers(context, text_item, cursor_.CurrentText(),
markers_to_paint, box_rect.offset, style,
DocumentMarkerPaintPhase::kBackground, nullptr);
- if (have_selection) {
- PaintSelection(context, cursor_, node, document, style,
- selection_style.fill_color, box_rect, *selection_status);
+ if (UNLIKELY(selection)) {
+ selection->ComputeSelectionRect(box_rect.offset);
+ selection->PaintSelectionBackground(context, node, document, style);
}
}
@@ -520,7 +605,7 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
}
const unsigned length = fragment_paint_info.to - fragment_paint_info.from;
- if (!paint_selected_text_only) {
+ if (!selection || !selection->ShouldPaintSelectedTextOnly()) {
// Paint text decorations except line-through.
DecorationInfo decoration_info;
bool has_line_through_decoration = false;
@@ -549,16 +634,9 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
unsigned start_offset = fragment_paint_info.from;
unsigned end_offset = fragment_paint_info.to;
- if (have_selection && paint_selected_text_separately) {
- // Paint only the text that is not selected.
- if (start_offset < selection_status->start) {
- text_painter.Paint(start_offset, selection_status->start, length,
- text_style, node_id);
- }
- if (selection_status->end < end_offset) {
- text_painter.Paint(selection_status->end, end_offset, length,
- text_style, node_id);
- }
+ if (UNLIKELY(selection && selection->ShouldPaintSelectedTextSeparately())) {
+ selection->PaintBeforeAndAfterSelectedText(
+ text_painter, start_offset, end_offset, length, text_style, node_id);
} else {
text_painter.Paint(start_offset, end_offset, length, text_style, node_id);
}
@@ -571,11 +649,12 @@ void NGTextFragmentPainter<Cursor>::Paint(const PaintInfo& paint_info,
}
}
- if (have_selection &&
- (paint_selected_text_only || paint_selected_text_separately)) {
+ if (UNLIKELY(selection && (selection->ShouldPaintSelectedTextOnly() ||
+ selection->ShouldPaintSelectedTextSeparately()))) {
// Paint only the text that is selected.
- text_painter.Paint(selection_status->start, selection_status->end, length,
- selection_style, node_id);
+ if (!selection->IsSelectionRectComputed())
+ selection->ComputeSelectionRect(box_rect.offset);
+ selection->PaintSelectedText(text_painter, length, text_style, node_id);
}
if (paint_info.phase != PaintPhase::kForeground)
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
index d1c4ab8c517..beddc4dc958 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_TEXT_FRAGMENT_PAINTER_H_
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
@@ -57,7 +58,10 @@ class NGTextFragmentPainter {
STACK_ALLOCATED();
public:
- explicit NGTextFragmentPainter(const Cursor&);
+ explicit NGTextFragmentPainter(const Cursor& cursor) : cursor_(cursor) {}
+ NGTextFragmentPainter(const Cursor& cursor,
+ const PhysicalOffset& parent_offset)
+ : cursor_(cursor), parent_offset_(parent_offset) {}
void Paint(const PaintInfo&, const PhysicalOffset& paint_offset);
@@ -80,6 +84,8 @@ class NGTextFragmentPainter {
const PhysicalOffset& paint_offset);
const Cursor& cursor_;
+ PhysicalOffset parent_offset_;
+ base::Optional<NGInlineCursor> inline_cursor_for_block_flow_;
};
extern template class NGTextFragmentPainter<NGTextPainterCursor>;
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
index 0dfa168b059..e1d5ac5fa23 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter_test.cc
@@ -6,6 +6,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -39,14 +40,14 @@ TEST_P(NGTextFragmentPainterTest, TestTextStyle) {
const LayoutNGBlockFlow& block_flow = ToLayoutNGBlockFlow(container);
InvalidateAll(RootPaintController());
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
Paint(IntRect(0, 0, 640, 480));
- const NGPaintFragment& root_fragment = *block_flow.PaintFragment();
- EXPECT_EQ(1u, root_fragment.Children().size());
- const NGPaintFragment& line_box_fragment = *root_fragment.FirstChild();
- EXPECT_EQ(1u, line_box_fragment.Children().size());
- const NGPaintFragment& text_fragment = *line_box_fragment.FirstChild();
+ NGInlineCursor cursor;
+ cursor.MoveTo(*block_flow.FirstChild());
+ const DisplayItemClient& text_fragment =
+ *cursor.Current().GetDisplayItemClient();
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
@@ -65,4 +66,21 @@ TEST_P(NGTextFragmentPainterTest, LineBreak) {
EXPECT_EQ(6u, RootPaintController().GetDisplayItemList().size());
}
+TEST_P(NGTextFragmentPainterTest, DegenerateUnderlineIntercepts) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ span {
+ font-size: 20px;
+ text-decoration: underline;
+ }
+ </style>
+ <span style="letter-spacing: -1e9999em;">a|b|c d{e{f{</span>
+ <span style="letter-spacing: 1e9999em;">a|b|c d{e{f{</span>
+ )HTML");
+ UpdateAllLifecyclePhasesForTest();
+ // Test for https://crbug.com/1043753: the underline intercepts are infinite
+ // due to letter spacing and this test passes if that does not cause a crash.
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
index 431ff2304ba..bb35f02d633 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.cc
@@ -40,6 +40,52 @@ void NGTextPainter::Paint(unsigned start_offset,
}
}
+// This function paints text twice with different styles in order to:
+// 1. Paint glyphs inside of |selection_rect| using |selection_style|, and
+// outside using |text_style|.
+// 2. Paint parts of a ligature glyph.
+void NGTextPainter::PaintSelectedText(unsigned start_offset,
+ unsigned end_offset,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ const TextPaintStyle& selection_style,
+ const PhysicalRect& selection_rect,
+ DOMNodeId node_id) {
+ if (!fragment_paint_info_.shape_result)
+ return;
+
+ // Use fast path if all glyphs fit in |selection_rect|. Note |text_bounds_| is
+ // the bounds of all glyphs of this text fragment, including characters before
+ // |start_offset| or after |end_offset|. Computing exact bounds is expensive
+ // that this code only checks bounds of all glyphs.
+ if (selection_rect.Contains(text_bounds_)) {
+ Paint(start_offset, end_offset, length, selection_style, node_id);
+ return;
+ }
+
+ // Adjust start/end offset when they are in the middle of a ligature. e.g.,
+ // when |start_offset| is between a ligature of "fi", it needs to be adjusted
+ // to before "f".
+ fragment_paint_info_.shape_result->ExpandRangeToIncludePartialGlyphs(
+ &start_offset, &end_offset);
+
+ // Because only a part of the text glyph can be selected, we need to draw
+ // the selection twice. First, draw the glyphs outside the selection area,
+ // with the original style.
+ FloatRect float_selection_rect(selection_rect);
+ {
+ GraphicsContextStateSaver state_saver(graphics_context_);
+ graphics_context_.ClipOut(float_selection_rect);
+ Paint(start_offset, end_offset, length, text_style, node_id);
+ }
+ // Then draw the glyphs inside the selection area, with the selection style.
+ {
+ GraphicsContextStateSaver state_saver(graphics_context_);
+ graphics_context_.Clip(float_selection_rect);
+ Paint(start_offset, end_offset, length, selection_style, node_id);
+ }
+}
+
template <NGTextPainter::PaintInternalStep step>
void NGTextPainter::PaintInternalFragment(
unsigned from,
diff --git a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
index dc8c2bd5f19..b9b96936f54 100644
--- a/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/ng/ng_text_painter.h
@@ -44,6 +44,14 @@ class CORE_EXPORT NGTextPainter : public TextPainterBase {
const TextPaintStyle&,
DOMNodeId);
+ void PaintSelectedText(unsigned start_offset,
+ unsigned end_offset,
+ unsigned length,
+ const TextPaintStyle& text_style,
+ const TextPaintStyle& selection_style,
+ const PhysicalRect& selection_rect,
+ DOMNodeId node_id);
+
private:
template <PaintInternalStep step>
void PaintInternalFragment(unsigned from, unsigned to, DOMNodeId node_id);
diff --git a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
index b903af4b71d..ca91cbaff74 100644
--- a/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/nine_piece_image_painter.cc
@@ -177,8 +177,9 @@ bool NinePieceImagePainter::Paint(GraphicsContext& graphics_context,
// is one. For generated images, the actual image data (gradient stops, etc.)
// are scaled to effective zoom instead so we must take care not to cause
// scale of them again.
- IntSize image_size = RoundedIntSize(style_image->ImageSize(
- document, 1, border_image_rect.size.ToLayoutSize()));
+ IntSize image_size = RoundedIntSize(
+ style_image->ImageSize(document, 1, border_image_rect.size.ToLayoutSize(),
+ kRespectImageOrientation));
scoped_refptr<Image> image =
style_image->GetImage(observer, document, style, FloatSize(image_size));
if (!image)
diff --git a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
index d7e46c2cda9..e3f8aeb9891 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
@@ -228,9 +228,6 @@ ObjectPaintInvalidatorWithContext::ComputePaintInvalidationReason() {
context_.fragment_data->VisualRect().IsEmpty())
return PaintInvalidationReason::kNone;
- if (object_.PaintedOutputOfObjectHasNoEffectRegardlessOfSize())
- return PaintInvalidationReason::kNone;
-
// Force full paint invalidation if the outline may be affected by descendants
// and this object is marked for checking paint invalidation for any reason.
if (object_.OutlineMayBeAffectedByDescendants() ||
diff --git a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
index 179caace7b3..a84527533ee 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
@@ -56,7 +56,9 @@ TEST_F(ObjectPaintInvalidatorTest,
style='position: relative'></div>
<div
id='non-stacked-layered-child-of-composited-non-stacking-context'
- style='overflow: scroll'></div>
+ style='overflow: scroll'>
+ <div style="height:40px"></div>
+ </div>
</div>
</div>
)HTML");
@@ -326,7 +328,8 @@ TEST_F(ObjectPaintInvalidatorTest, InvalidatePaintRectangle) {
EXPECT_TRUE(target->ShouldCheckForPaintInvalidation());
EXPECT_TRUE(IsValidDisplayItemClient(target));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_EQ(PhysicalRect(), target->PartialInvalidationLocalRect());
EXPECT_EQ(IntRect(18, 18, 80, 80), target->PartialInvalidationVisualRect());
EXPECT_FALSE(IsValidDisplayItemClient(target));
@@ -334,7 +337,8 @@ TEST_F(ObjectPaintInvalidatorTest, InvalidatePaintRectangle) {
target->InvalidatePaintRectangle(PhysicalRect(30, 30, 50, 80));
EXPECT_EQ(PhysicalRect(30, 30, 50, 80),
target->PartialInvalidationLocalRect());
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// PartialInvalidationVisualRect should accumulate until painting.
EXPECT_EQ(IntRect(18, 18, 80, 100), target->PartialInvalidationVisualRect());
diff --git a/chromium/third_party/blink/renderer/core/paint/object_painter.cc b/chromium/third_party/blink/renderer/core/paint/object_painter.cc
index 42c8caf0167..633e6518e9e 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_painter.cc
@@ -99,10 +99,10 @@ void ObjectPainter::AddURLRectIfNeeded(const PaintInfo& paint_info,
}
void ObjectPainter::PaintAllPhasesAtomically(const PaintInfo& paint_info) {
- // Pass kSelection and kTextClip to the descendants so that
+ // Pass kSelectionDragImage and kTextClip to the descendants so that
// they will paint for selection and text clip respectively. We don't need
// complete painting for these phases.
- if (paint_info.phase == PaintPhase::kSelection ||
+ if (paint_info.phase == PaintPhase::kSelectionDragImage ||
paint_info.phase == PaintPhase::kTextClip) {
layout_object_.Paint(paint_info);
return;
diff --git a/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc
index f165ceeecf8..096fd2913e1 100644
--- a/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/object_painter_base.cc
@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/paint/object_painter_base.h"
+#include "base/optional.h"
#include "third_party/blink/renderer/core/paint/box_border_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/style/border_edge.h"
@@ -12,6 +13,8 @@
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/native_theme/native_theme.h"
namespace blink {
@@ -486,6 +489,46 @@ void DrawSolidBoxSide(GraphicsContext& graphics_context,
FillQuad(graphics_context, quad, color, antialias);
}
+float GetFocusRingBorderRadius(const ComputedStyle& style) {
+ // Default style is border-radius equal to outline width.
+ float border_radius = style.GetOutlineStrokeWidthForFocusRing();
+
+ if (::features::IsFormControlsRefreshEnabled() && !style.HasAuthorBorder() &&
+ style.HasEffectiveAppearance()) {
+ // For the elements that have not been styled and that have an appearance,
+ // the focus ring should use the same border radius as the one used for
+ // drawing the element.
+ base::Optional<ui::NativeTheme::Part> part;
+ switch (style.EffectiveAppearance()) {
+ case kCheckboxPart:
+ part = ui::NativeTheme::kCheckbox;
+ break;
+ case kRadioPart:
+ part = ui::NativeTheme::kRadio;
+ break;
+ case kPushButtonPart:
+ case kSquareButtonPart:
+ case kButtonPart:
+ part = ui::NativeTheme::kPushButton;
+ break;
+ case kTextFieldPart:
+ case kTextAreaPart:
+ case kSearchFieldPart:
+ part = ui::NativeTheme::kTextField;
+ break;
+ default:
+ break;
+ }
+ if (part) {
+ return ui::NativeTheme::GetInstanceForWeb()->GetBorderRadiusForPart(
+ part.value(), style.Width().GetFloatValue(),
+ style.Height().GetFloatValue(), style.EffectiveZoom());
+ }
+ }
+
+ return border_radius;
+}
+
} // anonymous namespace
void ObjectPainterBase::PaintOutlineRects(
@@ -498,9 +541,17 @@ void ObjectPainterBase::PaintOutlineRects(
Color color = style.VisitedDependentColor(GetCSSPropertyOutlineColor());
if (style.OutlineStyleIsAuto()) {
+ // Logic in draw focus ring is dependent on whether the border is large
+ // enough to have an inset outline. Use the smallest border edge for that
+ // test.
+ float min_border_width =
+ std::min(std::min(style.BorderTopWidth(), style.BorderBottomWidth()),
+ std::min(style.BorderLeftWidth(), style.BorderRightWidth()));
+ float border_radius = GetFocusRingBorderRadius(style);
paint_info.context.DrawFocusRing(
pixel_snapped_outline_rects, style.GetOutlineStrokeWidthForFocusRing(),
- style.OutlineOffset(), color,
+ style.OutlineOffset(), style.GetDefaultOffsetForFocusRing(),
+ border_radius, min_border_width, color,
LayoutTheme::GetTheme().IsFocusRingOutset());
return;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index c0b3b43e62d..773e223519d 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -163,6 +163,20 @@ TEST_P(PaintAndRasterInvalidationTest, IncrementalInvalidationMixed) {
GetDocument().View()->SetTracksRasterInvalidations(false);
}
+TEST_P(PaintAndRasterInvalidationTest, ResizeEmptyContent) {
+ SetUpHTML(*this);
+ Element* target = GetDocument().getElementById("target");
+ // Make the box empty.
+ target->setAttribute(html_names::kClassAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+
+ GetDocument().View()->SetTracksRasterInvalidations(true);
+ target->setAttribute(html_names::kStyleAttr, "width: 100px; height: 80px");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_FALSE(GetRasterInvalidationTracking()->HasInvalidations());
+ GetDocument().View()->SetTracksRasterInvalidations(false);
+}
+
TEST_P(PaintAndRasterInvalidationTest, SubpixelVisualRectChagne) {
SetUpHTML(*this);
Element* target = GetDocument().getElementById("target");
@@ -286,7 +300,7 @@ TEST_P(PaintAndRasterInvalidationTest, ResizeRotatedChild) {
Element* target = GetDocument().getElementById("target");
target->setAttribute(html_names::kStyleAttr,
"transform: rotate(45deg); width: 200px");
- target->SetInnerHTMLFromString(
+ target->setInnerHTML(
"<div id=child style='width: 50px; height: 50px; background: "
"red'></div>");
UpdateAllLifecyclePhasesForTest();
@@ -315,11 +329,6 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedLayoutViewResize) {
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
GetLayoutView().GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- const auto* mapping = GetLayoutView().Layer()->GetCompositedLayerMapping();
- EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
- EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
- }
// Resize the content.
GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -350,11 +359,6 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedLayoutViewGradientResize) {
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
GetLayoutView().GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- const auto* mapping = GetLayoutView().Layer()->GetCompositedLayerMapping();
- EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
- EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
- }
// Resize the content.
GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -395,9 +399,15 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewResize) {
UpdateAllLifecyclePhasesForTest();
Element* iframe = GetDocument().getElementById("iframe");
Element* content = ChildDocument().getElementById("content");
- EXPECT_EQ(GetLayoutView(),
- content->GetLayoutObject()->ContainerForPaintInvalidation());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(GetLayoutView(),
+ content->GetLayoutObject()->ContainerForPaintInvalidation());
+ }
EXPECT_EQ(kBackgroundPaintInScrollingContents,
+ content->GetLayoutObject()
+ ->View()
+ ->ComputeBackgroundPaintLocationIfComposited());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
content->GetLayoutObject()->View()->GetBackgroundPaintLocation());
// Resize the content.
@@ -414,11 +424,7 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewResize) {
UpdateAllLifecyclePhasesForTest();
// The iframe doesn't have anything visible by itself, so we only issue
// raster invalidation for the frame contents.
- const auto* iframe_layout_view = content->GetLayoutObject()->View();
- const auto* client = RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
- ? &iframe_layout_view->GetScrollableArea()
- ->GetScrollingBackgroundDisplayItemClient()
- : iframe_layout_view;
+ const auto* client = content->GetLayoutObject()->View();
EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
UnorderedElementsAre(RasterInvalidationInfo{
client, client->DebugName(), IntRect(0, 100, 100, 100),
@@ -426,6 +432,31 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewResize) {
GetDocument().View()->SetTracksRasterInvalidations(false);
}
+TEST_P(PaintAndRasterInvalidationTest, FullInvalidationWithHTMLTransform) {
+ GetDocument().documentElement()->setAttribute(html_names::kStyleAttr,
+ "transform: scale(0.5)");
+ const DisplayItemClient* client =
+ &GetDocument()
+ .View()
+ ->GetLayoutView()
+ ->GetScrollableArea()
+ ->GetScrollingBackgroundDisplayItemClient();
+ UpdateAllLifecyclePhasesForTest();
+
+ GetDocument().View()->SetTracksRasterInvalidations(true);
+ GetDocument().View()->Resize(WebSize(500, 500));
+ UpdateAllLifecyclePhasesForTest();
+
+ EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+ UnorderedElementsAre(
+ RasterInvalidationInfo{client, client->DebugName(),
+ IntRect(0, 0, 500, 500),
+ PaintInvalidationReason::kBackground},
+ RasterInvalidationInfo{
+ client, client->DebugName(), IntRect(0, 0, 500, 500),
+ PaintInvalidationReason::kPaintProperty}));
+}
+
TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewGradientResize) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -448,36 +479,20 @@ TEST_P(PaintAndRasterInvalidationTest, NonCompositedLayoutViewGradientResize) {
UpdateAllLifecyclePhasesForTest();
Element* iframe = GetDocument().getElementById("iframe");
Element* content = ChildDocument().getElementById("content");
- LayoutView* frame_layout_view = content->GetLayoutObject()->View();
- EXPECT_EQ(GetLayoutView(),
- content->GetLayoutObject()->ContainerForPaintInvalidation());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(GetLayoutView(),
+ content->GetLayoutObject()->ContainerForPaintInvalidation());
+ }
// Resize the content.
GetDocument().View()->SetTracksRasterInvalidations(true);
content->setAttribute(html_names::kStyleAttr, "height: 500px");
UpdateAllLifecyclePhasesForTest();
- const auto* client = RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
- ? &frame_layout_view->GetScrollableArea()
- ->GetScrollingBackgroundDisplayItemClient()
- : frame_layout_view;
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // The duplication is because we invalidated both the old visual rect and
- // the new visual rect of the scrolling background display item which
- // changed size, and then both mapped to the same rect in the layer.
- EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
- UnorderedElementsAre(
- RasterInvalidationInfo{
- client, client->DebugName(), IntRect(0, 0, 100, 100),
- PaintInvalidationReason::kBackground},
- RasterInvalidationInfo{
- client, client->DebugName(), IntRect(0, 0, 100, 100),
- PaintInvalidationReason::kBackground}));
- } else {
- EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
- UnorderedElementsAre(RasterInvalidationInfo{
- client, client->DebugName(), IntRect(0, 0, 100, 100),
- PaintInvalidationReason::kBackground}));
- }
+ const auto* client = content->GetLayoutObject()->View();
+ EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
+ UnorderedElementsAre(RasterInvalidationInfo{
+ client, client->DebugName(), IntRect(0, 0, 100, 100),
+ PaintInvalidationReason::kBackground}));
GetDocument().View()->SetTracksRasterInvalidations(false);
// Resize the iframe.
@@ -499,7 +514,8 @@ TEST_P(PaintAndRasterInvalidationTest,
Element* target = GetDocument().getElementById("target");
target->setAttribute(html_names::kClassAttr,
"solid composited scroll local-attachment border");
- target->SetInnerHTMLFromString(
+ UpdateAllLifecyclePhasesForTest();
+ target->setInnerHTML(
"<div id=child style='width: 500px; height: 500px'></div>",
ASSERT_NO_EXCEPTION);
Element* child = GetDocument().getElementById("child");
@@ -508,11 +524,6 @@ TEST_P(PaintAndRasterInvalidationTest,
auto* target_obj = ToLayoutBoxModelObject(target->GetLayoutObject());
EXPECT_EQ(kBackgroundPaintInScrollingContents,
target_obj->GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- const auto* mapping = target_obj->Layer()->GetCompositedLayerMapping();
- EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
- EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
- }
auto container_raster_invalidation_tracking =
[&]() -> const RasterInvalidationTracking* {
@@ -566,7 +577,7 @@ TEST_P(PaintAndRasterInvalidationTest,
Element* target = GetDocument().getElementById("target");
target->setAttribute(html_names::kClassAttr,
"gradient composited scroll local-attachment border");
- target->SetInnerHTMLFromString(
+ target->setInnerHTML(
"<div id='child' style='width: 500px; height: 500px'></div>",
ASSERT_NO_EXCEPTION);
Element* child = GetDocument().getElementById("child");
@@ -597,11 +608,6 @@ TEST_P(PaintAndRasterInvalidationTest,
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
target_obj->GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- const auto* mapping = target_obj->Layer()->GetCompositedLayerMapping();
- EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
- EXPECT_FALSE(mapping->BackgroundPaintsOntoGraphicsLayer());
- }
// No invalidation on the container layer.
EXPECT_FALSE(container_raster_invalidation_tracking()->HasInvalidations());
@@ -635,14 +641,18 @@ TEST_P(PaintAndRasterInvalidationTest,
Element* target = GetDocument().getElementById("target");
auto* object = target->GetLayoutObject();
target->setAttribute(html_names::kClassAttr, "solid local-attachment scroll");
- target->SetInnerHTMLFromString(
+ target->setInnerHTML(
"<div id=child style='width: 500px; height: 500px'></div>",
ASSERT_NO_EXCEPTION);
Element* child = GetDocument().getElementById("child");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(&GetLayoutView(), object->ContainerForPaintInvalidation());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ EXPECT_EQ(&GetLayoutView(), object->ContainerForPaintInvalidation());
EXPECT_EQ(kBackgroundPaintInScrollingContents,
- ToLayoutBoxModelObject(object)->GetBackgroundPaintLocation());
+ ToLayoutBoxModelObject(object)
+ ->ComputeBackgroundPaintLocationIfComposited());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
+ object->GetBackgroundPaintLocation());
// Resize the content.
GetDocument().View()->SetTracksRasterInvalidations(true);
@@ -671,8 +681,8 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedSolidBackgroundResize) {
SetUpHTML(*this);
Element* target = GetDocument().getElementById("target");
target->setAttribute(html_names::kClassAttr, "solid composited scroll");
- target->SetInnerHTMLFromString("<div style='height: 500px'></div>",
- ASSERT_NO_EXCEPTION);
+ target->setInnerHTML("<div style='height: 500px'></div>",
+ ASSERT_NO_EXCEPTION);
UpdateAllLifecyclePhasesForTest();
// Resize the scroller.
@@ -685,11 +695,6 @@ TEST_P(PaintAndRasterInvalidationTest, CompositedSolidBackgroundResize) {
EXPECT_EQ(
kBackgroundPaintInScrollingContents | kBackgroundPaintInGraphicsLayer,
target_object->GetBackgroundPaintLocation());
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- const auto* mapping = target_object->Layer()->GetCompositedLayerMapping();
- EXPECT_TRUE(mapping->BackgroundPaintsOntoScrollingContentsLayer());
- EXPECT_TRUE(mapping->BackgroundPaintsOntoGraphicsLayer());
- }
const auto* contents_raster_invalidation_tracking =
RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
@@ -767,15 +772,19 @@ TEST_P(PaintAndRasterInvalidationTest,
Element* iframe = GetDocument().getElementById("iframe");
LayoutView* child_layout_view = ChildDocument().GetLayoutView();
- EXPECT_EQ(GetDocument().GetLayoutView(),
- &child_layout_view->ContainerForPaintInvalidation());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(GetDocument().GetLayoutView(),
+ &child_layout_view->ContainerForPaintInvalidation());
+ }
EXPECT_EQ(IntRect(0, 0, 100, 100),
child_layout_view->FirstFragment().VisualRect());
iframe->setAttribute(html_names::kStyleAttr, "border: 20px solid blue");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(GetDocument().GetLayoutView(),
- &child_layout_view->ContainerForPaintInvalidation());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_EQ(GetDocument().GetLayoutView(),
+ &child_layout_view->ContainerForPaintInvalidation());
+ }
EXPECT_EQ(IntRect(0, 0, 100, 100),
child_layout_view->FirstFragment().VisualRect());
}
@@ -927,7 +936,8 @@ TEST_P(PaintAndRasterInvalidationTest, PaintPropertyChange) {
auto* layer = ToLayoutBoxModelObject(object)->Layer();
GetDocument().View()->SetTracksRasterInvalidations(true);
target->setAttribute(html_names::kStyleAttr, "transform: scale(3)");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(layer->SelfNeedsRepaint());
const auto* transform =
object->FirstFragment().PaintProperties()->Transform();
@@ -963,7 +973,8 @@ TEST_P(PaintAndRasterInvalidationTest, ResizeContainerOfFixedSizeSVG) {
GetDocument().View()->SetTracksRasterInvalidations(true);
target->setAttribute(html_names::kStyleAttr, "width: 200px; height: 200px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// We don't invalidate paint of the SVG rect.
EXPECT_TRUE(static_cast<const DisplayItemClient*>(rect)->IsValid());
@@ -1115,7 +1126,8 @@ TEST_F(PaintInvalidatorCustomClientTest,
ResetInvalidationRecorded();
target->setAttribute(html_names::kStyleAttr, "opacity: 0.98");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(
GetDocument().View()->GetLayoutView()->Layer()->DescendantNeedsRepaint());
EXPECT_TRUE(InvalidationRecorded());
@@ -1123,7 +1135,8 @@ TEST_F(PaintInvalidatorCustomClientTest,
ResetInvalidationRecorded();
// Let PrePaintTreeWalk do something instead of no-op.
GetDocument().View()->SetNeedsPaintPropertyUpdate();
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// The layer DescendantNeedsRepaint flag is only cleared after paint.
EXPECT_TRUE(
GetDocument().View()->GetLayoutView()->Layer()->DescendantNeedsRepaint());
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
index d9c7752ecf8..cafc50592fd 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
@@ -58,37 +59,39 @@ TEST_P(PaintControllerPaintTest, InlineRelayout) {
auto& div_block =
*To<LayoutBlock>(GetDocument().body()->firstChild()->GetLayoutObject());
LayoutText& text = *ToLayoutText(div_block.FirstChild());
- DisplayItemClient& first_text_box =
- text.FirstInlineFragment()
- ? (DisplayItemClient&)*text.FirstInlineFragment()
- : (DisplayItemClient&)*text.FirstTextBox();
+ const DisplayItemClient* first_text_box = text.FirstTextBox();
+ if (text.IsInLayoutNGInlineFormattingContext()) {
+ NGInlineCursor cursor;
+ cursor.MoveTo(text);
+ first_text_box = cursor.Current().GetDisplayItemClient();
+ }
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
- IsSameId(&first_text_box, kForegroundType)));
+ IsSameId(first_text_box, kForegroundType)));
div.setAttribute(html_names::kStyleAttr, "width: 10px; height: 200px");
UpdateAllLifecyclePhasesForTest();
LayoutText& new_text = *ToLayoutText(div_block.FirstChild());
- DisplayItemClient& new_first_text_box =
- new_text.FirstInlineFragment()
- ? (DisplayItemClient&)*new_text.FirstInlineFragment()
- : (DisplayItemClient&)*text.FirstTextBox();
- DisplayItemClient& second_text_box =
- new_text.FirstInlineFragment()
- ? (DisplayItemClient&)*NGPaintFragment::
- TraverseNextForSameLayoutObject::Next(
- new_text.FirstInlineFragment())
- : (DisplayItemClient&)*new_text.FirstTextBox()
- ->NextForSameLayoutObject();
+ const DisplayItemClient* new_first_text_box = text.FirstTextBox();
+ const DisplayItemClient* second_text_box = nullptr;
+ if (!text.IsInLayoutNGInlineFormattingContext()) {
+ second_text_box = new_text.FirstTextBox()->NextForSameLayoutObject();
+ } else {
+ NGInlineCursor cursor;
+ cursor.MoveTo(text);
+ new_first_text_box = cursor.Current().GetDisplayItemClient();
+ cursor.MoveToNextForSameLayoutObject();
+ second_text_box = cursor.Current().GetDisplayItemClient();
+ }
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
- IsSameId(&new_first_text_box, kForegroundType),
- IsSameId(&second_text_box, kForegroundType)));
+ IsSameId(new_first_text_box, kForegroundType),
+ IsSameId(second_text_box, kForegroundType)));
}
TEST_P(PaintControllerPaintTest, ChunkIdClientCacheFlag) {
@@ -156,21 +159,47 @@ TEST_P(PaintControllerPaintTestForCAP, FrameScrollingContents) {
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(
- IsSameId(&GetLayoutView(), kScrollHitTestType),
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(&div1, kBackgroundType), IsSameId(&div2, kBackgroundType)));
+ HitTestData view_scroll_hit_test;
+ view_scroll_hit_test.scroll_translation =
+ &GetLayoutView().FirstFragment().ContentsProperties().Transform();
+ view_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 800, 600);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(
+ 0, 0,
+ PaintChunk::Id(GetLayoutView(), DisplayItem::kScrollHitTest),
+ GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
+ &view_scroll_hit_test, IntRect(0, 0, 800, 600)),
+ IsPaintChunk(0, 3,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties())));
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(5000, 5000), kProgrammaticScroll);
+ ScrollOffset(5000, 5000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(
- IsSameId(&GetLayoutView(), kScrollHitTestType),
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(&div2, kBackgroundType), IsSameId(&div3, kBackgroundType),
IsSameId(&div4, kBackgroundType)));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(
+ 0, 0,
+ PaintChunk::Id(GetLayoutView(), DisplayItem::kScrollHitTest),
+ GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
+ &view_scroll_hit_test, IntRect(0, 0, 800, 600)),
+ IsPaintChunk(0, 4,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties())));
}
TEST_P(PaintControllerPaintTestForCAP, BlockScrollingNonLayeredContents) {
@@ -201,11 +230,34 @@ TEST_P(PaintControllerPaintTestForCAP, BlockScrollingNonLayeredContents) {
RootPaintController().GetDisplayItemList(),
ElementsAre(
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
- IsSameId(&container, kScrollHitTestType),
IsSameId(&div1, kBackgroundType), IsSameId(&div2, kBackgroundType)));
-
- container.GetScrollableArea()->SetScrollOffset(ScrollOffset(5000, 5000),
- kProgrammaticScroll);
+ HitTestData container_scroll_hit_test;
+ container_scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ container_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 200, 200)),
+ IsPaintChunk(1, 1,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &container_scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 1, 3,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ container.FirstFragment().ContentsProperties())));
+
+ container.GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(5000, 5000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Cull rect after scroll: (1000,1000 8100x8100)
@@ -213,9 +265,28 @@ TEST_P(PaintControllerPaintTestForCAP, BlockScrollingNonLayeredContents) {
RootPaintController().GetDisplayItemList(),
ElementsAre(
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
- IsSameId(&container, kScrollHitTestType),
IsSameId(&div2, kBackgroundType), IsSameId(&div3, kBackgroundType),
IsSameId(&div4, kBackgroundType)));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 200, 200)),
+ IsPaintChunk(1, 1,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &container_scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 1, 4,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ container.FirstFragment().ContentsProperties())));
}
TEST_P(PaintControllerPaintTestForCAP, ScrollHitTestOrder) {
@@ -243,14 +314,42 @@ TEST_P(PaintControllerPaintTestForCAP, ScrollHitTestOrder) {
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(
- IsSameId(&GetLayoutView(), kScrollHitTestType),
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(&container, kBackgroundType),
- IsSameId(&container, kScrollHitTestType),
- IsSameId(&container.GetScrollableArea()
- ->GetScrollingBackgroundDisplayItemClient(),
- kBackgroundType),
IsSameId(&child, kBackgroundType)));
+ HitTestData view_scroll_hit_test;
+ view_scroll_hit_test.scroll_translation =
+ &GetLayoutView().FirstFragment().ContentsProperties().Transform();
+ view_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 800, 600);
+ HitTestData container_scroll_hit_test;
+ container_scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ container_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(
+ 0, 0,
+ PaintChunk::Id(GetLayoutView(), DisplayItem::kScrollHitTest),
+ GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
+ &view_scroll_hit_test, IntRect(0, 0, 800, 600)),
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 200, 200)),
+ IsPaintChunk(2, 2,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &container_scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 2, 3,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ container.FirstFragment().ContentsProperties())));
}
TEST_P(PaintControllerPaintTestForCAP, NonStackingScrollHitTestOrder) {
@@ -274,16 +373,17 @@ TEST_P(PaintControllerPaintTestForCAP, NonStackingScrollHitTestOrder) {
</div>
)HTML");
- auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+ auto& html = *GetDocument().documentElement()->GetLayoutBox();
+ auto& container = *ToLayoutBox(GetLayoutObjectByElementId("container"));
auto& child = *GetLayoutObjectByElementId("child");
- auto& neg_z_child = *GetLayoutObjectByElementId("negZChild");
- auto& pos_z_child = *GetLayoutObjectByElementId("posZChild");
+ auto& neg_z_child = *ToLayoutBox(GetLayoutObjectByElementId("negZChild"));
+ auto& pos_z_child = *ToLayoutBox(GetLayoutObjectByElementId("posZChild"));
// Container is not a stacking context because no z-index is auto.
// Negative z-index descendants are painted before the background and
// positive z-index descendants are painted after the background. Scroll hit
// testing should hit positive descendants, the container, and then negative
- // descendants so the ScrollHitTest item should be immediately after the
+ // descendants so the scroll hit test should be immediately after the
// background.
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
@@ -291,12 +391,45 @@ TEST_P(PaintControllerPaintTestForCAP, NonStackingScrollHitTestOrder) {
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(&neg_z_child, kBackgroundType),
IsSameId(&container, kBackgroundType),
- IsSameId(&container, kScrollHitTestType),
- IsSameId(&container.GetScrollableArea()
- ->GetScrollingBackgroundDisplayItemClient(),
- kBackgroundType),
IsSameId(&child, kBackgroundType),
IsSameId(&pos_z_child, kBackgroundType)));
+ HitTestData container_scroll_hit_test;
+ container_scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ container_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*neg_z_child.Layer(), DisplayItem::kLayerChunk),
+ neg_z_child.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(
+ 2, 2,
+ PaintChunk::Id(*html.Layer(), DisplayItem::kLayerChunkForeground),
+ html.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 800, 200)),
+ IsPaintChunk(
+ 2, 3,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 200, 200)),
+ IsPaintChunk(3, 3,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &container_scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 3, 4,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ container.FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 4, 5,
+ PaintChunk::Id(*pos_z_child.Layer(), DisplayItem::kLayerChunk),
+ pos_z_child.FirstFragment().LocalBorderBoxProperties())));
}
TEST_P(PaintControllerPaintTestForCAP, StackingScrollHitTestOrder) {
@@ -320,10 +453,10 @@ TEST_P(PaintControllerPaintTestForCAP, StackingScrollHitTestOrder) {
</div>
)HTML");
- auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+ auto& container = *ToLayoutBox(GetLayoutObjectByElementId("container"));
auto& child = *GetLayoutObjectByElementId("child");
- auto& neg_z_child = *GetLayoutObjectByElementId("negZChild");
- auto& pos_z_child = *GetLayoutObjectByElementId("posZChild");
+ auto& neg_z_child = *ToLayoutBox(GetLayoutObjectByElementId("negZChild"));
+ auto& pos_z_child = *ToLayoutBox(GetLayoutObjectByElementId("posZChild"));
// Container is a stacking context because z-index is non-auto.
// Both positive and negative z-index descendants are painted after the
@@ -334,13 +467,47 @@ TEST_P(PaintControllerPaintTestForCAP, StackingScrollHitTestOrder) {
ElementsAre(
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(&container, kBackgroundType),
- IsSameId(&container, kScrollHitTestType),
IsSameId(&container.GetScrollableArea()
->GetScrollingBackgroundDisplayItemClient(),
kBackgroundType),
IsSameId(&neg_z_child, kBackgroundType),
IsSameId(&child, kBackgroundType),
IsSameId(&pos_z_child, kBackgroundType)));
+ HitTestData container_scroll_hit_test;
+ container_scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ container_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 200, 200)),
+ IsPaintChunk(2, 2,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &container_scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(2, 3,
+ PaintChunk::Id(container, kScrollingBackgroundChunkType),
+ container.FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 3, 4,
+ PaintChunk::Id(*neg_z_child.Layer(), DisplayItem::kLayerChunk),
+ neg_z_child.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(
+ 4, 5,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ container.FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 5, 6,
+ PaintChunk::Id(*pos_z_child.Layer(), DisplayItem::kLayerChunk),
+ pos_z_child.FirstFragment().LocalBorderBoxProperties())));
}
TEST_P(PaintControllerPaintTestForCAP,
@@ -365,20 +532,57 @@ TEST_P(PaintControllerPaintTestForCAP,
</div>
)HTML");
- auto& container = *To<LayoutBlock>(GetLayoutObjectByElementId("container"));
+ auto& html = *GetDocument().documentElement()->GetLayoutBox();
+ auto& container = *ToLayoutBox(GetLayoutObjectByElementId("container"));
auto& child = *GetLayoutObjectByElementId("child");
- auto& neg_z_child = *GetLayoutObjectByElementId("negZChild");
- auto& pos_z_child = *GetLayoutObjectByElementId("posZChild");
+ auto& neg_z_child = *ToLayoutBox(GetLayoutObjectByElementId("negZChild"));
+ auto& pos_z_child = *ToLayoutBox(GetLayoutObjectByElementId("posZChild"));
- // Even though container does not paint a background, the scroll hit test item
+ // Even though container does not paint a background, the scroll hit test
// should still be between the negative z-index child and the regular child.
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
IsSameId(&neg_z_child, kBackgroundType),
- IsSameId(&container, kScrollHitTestType),
IsSameId(&child, kBackgroundType),
IsSameId(&pos_z_child, kBackgroundType)));
+ HitTestData container_scroll_hit_test;
+ container_scroll_hit_test.scroll_translation =
+ &container.FirstFragment().ContentsProperties().Transform();
+ container_scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 200, 200);
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ DisplayItem::kDocumentBackground),
+ GetLayoutView().FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*neg_z_child.Layer(), DisplayItem::kLayerChunk),
+ neg_z_child.FirstFragment().LocalBorderBoxProperties()),
+ IsPaintChunk(
+ 2, 2,
+ PaintChunk::Id(*html.Layer(), DisplayItem::kLayerChunkForeground),
+ html.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 800, 200)),
+ IsPaintChunk(
+ 2, 2,
+ PaintChunk::Id(*container.Layer(), DisplayItem::kLayerChunk),
+ container.FirstFragment().LocalBorderBoxProperties(), nullptr,
+ IntRect(0, 0, 200, 200)),
+ IsPaintChunk(2, 2,
+ PaintChunk::Id(container, DisplayItem::kScrollHitTest),
+ container.FirstFragment().LocalBorderBoxProperties(),
+ &container_scroll_hit_test, IntRect(0, 0, 200, 200)),
+ IsPaintChunk(
+ 2, 3,
+ PaintChunk::Id(container, kClippedContentsBackgroundChunkType),
+ container.FirstFragment().ContentsProperties()),
+ IsPaintChunk(
+ 3, 4,
+ PaintChunk::Id(*pos_z_child.Layer(), DisplayItem::kLayerChunk),
+ pos_z_child.FirstFragment().LocalBorderBoxProperties())));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
index c88fa5805fe..f87c116d72f 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_controller_paint_test.h
@@ -137,24 +137,10 @@ const DisplayItem::Type kNonScrollingBackgroundChunkType =
DisplayItem::PaintPhaseToDrawingType(PaintPhase::kSelfBlockBackgroundOnly);
const DisplayItem::Type kScrollingBackgroundChunkType =
DisplayItem::PaintPhaseToClipType(PaintPhase::kSelfBlockBackgroundOnly);
-const DisplayItem::Type kNonScrollingContentsBackgroundChunkType =
- DisplayItem::PaintPhaseToDrawingType(
- PaintPhase::kDescendantBlockBackgroundsOnly);
-const DisplayItem::Type kScrollingContentsBackgroundChunkType =
+const DisplayItem::Type kClippedContentsBackgroundChunkType =
DisplayItem::PaintPhaseToClipType(
PaintPhase::kDescendantBlockBackgroundsOnly);
-#define EXPECT_SUBSEQUENCE(client, expected_start, expected_end) \
- do { \
- auto* subsequence = GetSubsequenceMarkers(client); \
- ASSERT_NE(nullptr, subsequence); \
- EXPECT_EQ(static_cast<size_t>(expected_start), subsequence->start); \
- EXPECT_EQ(static_cast<size_t>(expected_end), subsequence->end); \
- } while (false)
-
-#define EXPECT_NO_SUBSEQUENCE(client) \
- EXPECT_EQ(nullptr, GetSubsequenceMarkers(client)
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_CONTROLLER_PAINT_TEST_H_
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_info.h b/chromium/third_party/blink/renderer/core/paint/paint_info.h
index 6927f0aed5a..7716d6e8cc0 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_info.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_info.h
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
// TODO(jchaffraix): Once we unify PaintBehavior and PaintLayerFlags, we should
// move PaintLayerFlags to PaintPhase and rename it. Thus removing the need for
// this #include
@@ -168,6 +169,17 @@ struct CORE_EXPORT PaintInfo {
return nullptr;
}
+ // Returns the FragmentData of the specified physical fragment. If fragment
+ // traversal is supported, it will map directly to the right FragmentData.
+ // Otherwise we'll fall back to matching against the current
+ // PaintLayerFragment.
+ const FragmentData* FragmentToPaint(
+ const NGPhysicalFragment& fragment) const {
+ if (fragment.CanTraverse())
+ return fragment.GetFragmentData();
+ return FragmentToPaint(*fragment.GetLayoutObject());
+ }
+
void SetFragmentLogicalTopInFlowThread(LayoutUnit fragment_logical_top) {
fragment_logical_top_in_flow_thread_ = fragment_logical_top;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
index 358f04b3639..12031a700f8 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.cc
@@ -14,7 +14,10 @@
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_table_section.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/page/link_highlight.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -131,22 +134,43 @@ PaintInvalidatorContext::ParentContextAccessor::ParentContext() const {
IntRect PaintInvalidator::ComputeVisualRect(
const LayoutObject& object,
+ const NGPrePaintInfo* pre_paint_info,
const PaintInvalidatorContext& context) {
if (object.IsSVGChild()) {
return context.MapLocalRectToVisualRectForSVGChild(
object, SVGLayoutSupport::LocalVisualRect(object));
}
- return context.MapLocalRectToVisualRect(object, object.LocalVisualRect());
+ PhysicalRect rect;
+ if (pre_paint_info) {
+ const NGFragmentChildIterator& iterator = pre_paint_info->iterator;
+ DCHECK(iterator->BoxFragment() || iterator->FragmentItem());
+ if (object.StyleRef().Visibility() == EVisibility::kVisible) {
+ if (const auto* box_fragment = iterator->BoxFragment())
+ rect = box_fragment->InkOverflow();
+ else
+ rect = iterator->FragmentItem()->InkOverflow();
+ // The paint offset of text and non-atomic inlines are special; they are
+ // set to the paint offset of their container. Add the offset to the
+ // fragment now, to set the correct visual rectangle.
+ if (!object.IsBox())
+ rect.Move(iterator->Link().offset);
+ }
+ } else {
+ rect = object.LocalVisualRect();
+ }
+ return context.MapLocalRectToVisualRect(object, rect);
}
void PaintInvalidator::UpdatePaintingLayer(const LayoutObject& object,
- PaintInvalidatorContext& context) {
+ PaintInvalidatorContext& context,
+ bool is_ng_painting) {
if (object.HasLayer() &&
ToLayoutBoxModelObject(object).HasSelfPaintingLayer()) {
context.painting_layer = ToLayoutBoxModelObject(object).Layer();
- } else if (object.IsColumnSpanAll() ||
- object.IsFloatingWithNonContainingBlockParent()) {
+ } else if (!is_ng_painting &&
+ (object.IsColumnSpanAll() ||
+ object.IsFloatingWithNonContainingBlockParent())) {
// See |LayoutObject::PaintingLayer| for the special-cases of floating under
// inline and multicolumn.
// Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
@@ -164,47 +188,24 @@ void PaintInvalidator::UpdatePaintingLayer(const LayoutObject& object,
IsLayoutNGContainingBlock(object.ContainingBlock())))
context.painting_layer->SetNeedsPaintPhaseFloat();
- // Table collapsed borders are painted in PaintPhaseDescendantBlockBackgrounds
- // on the table's layer.
- if (object.IsTable() &&
- ToInterface<LayoutNGTableInterface>(object).HasCollapsedBorders())
- context.painting_layer->SetNeedsPaintPhaseDescendantBlockBackgrounds();
-
- // The following flags are for descendants of the layer object only.
- if (object == context.painting_layer->GetLayoutObject())
- return;
-
- if (object.IsTableSection()) {
- const auto& section = ToInterface<LayoutNGTableSectionInterface>(object);
- if (section.TableInterface()->HasColElements())
- context.painting_layer->SetNeedsPaintPhaseDescendantBlockBackgrounds();
- }
-
- if (object.StyleRef().HasOutline())
+ if (object != context.painting_layer->GetLayoutObject() &&
+ object.StyleRef().HasOutline())
context.painting_layer->SetNeedsPaintPhaseDescendantOutlines();
-
- if (object.HasBoxDecorationBackground()
- // We also paint non-overlay overflow controls in background phase.
- || (object.HasOverflowClip() && ToLayoutBox(object)
- .GetScrollableArea()
- ->HasNonOverlayOverflowControls())) {
- context.painting_layer->SetNeedsPaintPhaseDescendantBlockBackgrounds();
- } else {
- // Hit testing rects for touch action paint in the background phase.
- if (object.HasEffectiveAllowedTouchAction())
- context.painting_layer->SetNeedsPaintPhaseDescendantBlockBackgrounds();
- }
}
void PaintInvalidator::UpdatePaintInvalidationContainer(
const LayoutObject& object,
- PaintInvalidatorContext& context) {
+ PaintInvalidatorContext& context,
+ bool is_ng_painting) {
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
if (object.IsPaintInvalidationContainer()) {
context.paint_invalidation_container = ToLayoutBoxModelObject(&object);
if (object.StyleRef().IsStackingContext() || object.IsSVGRoot())
context.paint_invalidation_container_for_stacked_contents =
ToLayoutBoxModelObject(&object);
- } else if (object.IsLayoutView()) {
+ } else if (IsA<LayoutView>(object)) {
// paint_invalidation_container_for_stacked_contents is only for stacked
// descendants in its own frame, because it doesn't establish stacking
// context for stacked contents in sub-frames.
@@ -213,8 +214,9 @@ void PaintInvalidator::UpdatePaintInvalidationContainer(
context.paint_invalidation_container_for_stacked_contents =
context.paint_invalidation_container =
&object.ContainerForPaintInvalidation();
- } else if (object.IsColumnSpanAll() ||
- object.IsFloatingWithNonContainingBlockParent()) {
+ } else if (!is_ng_painting &&
+ (object.IsColumnSpanAll() ||
+ object.IsFloatingWithNonContainingBlockParent())) {
// In these cases, the object may belong to an ancestor of the current
// paint invalidation container, in paint order.
// Post LayoutNG the |LayoutObject::IsFloatingWithNonContainingBlockParent|
@@ -265,16 +267,27 @@ void PaintInvalidator::UpdatePaintInvalidationContainer(
}
void PaintInvalidator::UpdateVisualRect(const LayoutObject& object,
+ const NGPrePaintInfo* pre_paint_info,
FragmentData& fragment_data,
PaintInvalidatorContext& context) {
if (!context.NeedsVisualRectUpdate(object))
return;
DCHECK(context.tree_builder_context_);
- DCHECK(context.tree_builder_context_->current.paint_offset ==
- fragment_data.PaintOffset());
-
- fragment_data.SetVisualRect(ComputeVisualRect(object, context));
+ DCHECK(!pre_paint_info || &fragment_data == &pre_paint_info->fragment_data);
+
+ IntRect visual_rect = ComputeVisualRect(object, pre_paint_info, context);
+ if (pre_paint_info && !object.IsBox()) {
+ DCHECK(object.IsInline());
+ // Text and non-atomic inlines share the same FragmentData object per block
+ // fragment, and their FragmentData objects are reset when visiting their
+ // first fragment. So just add to the visual rectangle.
+ visual_rect.Unite(fragment_data.VisualRect());
+ } else {
+ DCHECK_EQ(context.tree_builder_context_->current.paint_offset,
+ fragment_data.PaintOffset());
+ }
+ fragment_data.SetVisualRect(visual_rect);
object.GetFrameView()->GetLayoutShiftTracker().NotifyObjectPrePaint(
object,
@@ -286,7 +299,7 @@ void PaintInvalidator::UpdateVisualRect(const LayoutObject& object,
// it has was inherited from the parent frame, and movements of a
// frame relative to its parent are tracked in the parent frame's
// LayoutShiftTracker, not the child frame's.
- object.IsLayoutView()
+ IsA<LayoutView>(object)
? FloatSize()
: context.tree_builder_context_->paint_offset_delta);
}
@@ -315,13 +328,14 @@ void PaintInvalidator::UpdateEmptyVisualRectFlag(
bool PaintInvalidator::InvalidatePaint(
const LayoutObject& object,
+ const NGPrePaintInfo* pre_paint_info,
const PaintPropertyTreeBuilderContext* tree_builder_context,
PaintInvalidatorContext& context) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
"PaintInvalidator::InvalidatePaint()", "object",
object.DebugName().Ascii());
- if (object.IsSVGHiddenContainer())
+ if (object.IsSVGHiddenContainer() || object.IsLayoutTableCol())
context.subtree_flags |= PaintInvalidatorContext::kSubtreeNoInvalidation;
if (context.subtree_flags & PaintInvalidatorContext::kSubtreeNoInvalidation)
@@ -329,8 +343,9 @@ bool PaintInvalidator::InvalidatePaint(
object.GetMutableForPainting().EnsureIsReadyForPaintInvalidation();
- UpdatePaintingLayer(object, context);
- UpdatePaintInvalidationContainer(object, context);
+ UpdatePaintingLayer(object, context, /* is_ng_painting */ !!pre_paint_info);
+ UpdatePaintInvalidationContainer(object, context,
+ /* is_ng_painting */ !!pre_paint_info);
UpdateEmptyVisualRectFlag(object, context);
if (!object.ShouldCheckForPaintInvalidation() && !context.NeedsSubtreeWalk())
@@ -346,38 +361,72 @@ bool PaintInvalidator::InvalidatePaint(
object.GetFrameView()->SetForeignLayerListNeedsUpdate();
}
- unsigned tree_builder_index = 0;
+ if (pre_paint_info) {
+ FragmentData& fragment_data = pre_paint_info->fragment_data;
+ if (!object.IsBox()) {
+ // Text and non-atomic inlines may generate multiple physical fragments,
+ // and we're updating the VisualRect in the FragmentData as we visit each
+ // of them. As such, the current VisualRect in FragmentData is possibly
+ // incomplete, so letting anyone use it for comparisons is meaningless.
+ // TODO(crbug.com/1043787): Fix this. The way we use FragmentData for
+ // non-atomic inlines is not ideal for how LayoutNG works.
+ context.old_visual_rect = IntRect();
+ } else {
+ context.old_visual_rect = fragment_data.VisualRect();
+ }
+ context.fragment_data = &fragment_data;
- for (auto* fragment_data = &object.GetMutableForPainting().FirstFragment();
- fragment_data;
- fragment_data = fragment_data->NextFragment(), tree_builder_index++) {
- context.old_visual_rect = fragment_data->VisualRect();
- context.fragment_data = fragment_data;
+#if DCHECK_IS_ON()
+ context.tree_builder_context_actually_needed_ =
+ tree_builder_context && tree_builder_context->is_actually_needed;
+#endif
+ if (tree_builder_context) {
+ DCHECK_EQ(tree_builder_context->fragments.size(), 1u);
+ context.tree_builder_context_ = &tree_builder_context->fragments[0];
+ context.old_paint_offset =
+ context.tree_builder_context_->old_paint_offset;
+ } else {
+ context.tree_builder_context_ = nullptr;
+ context.old_paint_offset = fragment_data.PaintOffset();
+ }
+
+ UpdateVisualRect(object, pre_paint_info, fragment_data, context);
+ object.InvalidatePaint(context);
+ } else {
+ unsigned tree_builder_index = 0;
- DCHECK(!tree_builder_context ||
- tree_builder_index < tree_builder_context->fragments.size());
+ for (auto* fragment_data = &object.GetMutableForPainting().FirstFragment();
+ fragment_data;
+ fragment_data = fragment_data->NextFragment(), tree_builder_index++) {
+ context.old_visual_rect = fragment_data->VisualRect();
+ context.fragment_data = fragment_data;
- {
+ DCHECK(!tree_builder_context ||
+ tree_builder_index < tree_builder_context->fragments.size());
+
+ {
#if DCHECK_IS_ON()
- context.tree_builder_context_actually_needed_ =
- tree_builder_context && tree_builder_context->is_actually_needed;
- FindObjectVisualRectNeedingUpdateScope finder(object, *fragment_data,
- context);
+ context.tree_builder_context_actually_needed_ =
+ tree_builder_context && tree_builder_context->is_actually_needed;
+ FindObjectVisualRectNeedingUpdateScope finder(object, *fragment_data,
+ context);
#endif
- if (tree_builder_context) {
- context.tree_builder_context_ =
- &tree_builder_context->fragments[tree_builder_index];
- context.old_paint_offset =
- context.tree_builder_context_->old_paint_offset;
- } else {
- context.tree_builder_context_ = nullptr;
- context.old_paint_offset = fragment_data->PaintOffset();
+ if (tree_builder_context) {
+ context.tree_builder_context_ =
+ &tree_builder_context->fragments[tree_builder_index];
+ context.old_paint_offset =
+ context.tree_builder_context_->old_paint_offset;
+ } else {
+ context.tree_builder_context_ = nullptr;
+ context.old_paint_offset = fragment_data->PaintOffset();
+ }
+
+ UpdateVisualRect(object, /* pre_paint_info */ nullptr, *fragment_data,
+ context);
}
- UpdateVisualRect(object, *fragment_data, context);
+ object.InvalidatePaint(context);
}
-
- object.InvalidatePaint(context);
}
auto reason = static_cast<const DisplayItemClient&>(object)
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h
index a8aed714d64..85e7d672bef 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_invalidator.h
@@ -152,6 +152,7 @@ class PaintInvalidator {
public:
// Returns true if the object is invalidated.
bool InvalidatePaint(const LayoutObject&,
+ const NGPrePaintInfo*,
const PaintPropertyTreeBuilderContext*,
PaintInvalidatorContext&);
@@ -164,14 +165,18 @@ class PaintInvalidator {
friend class PrePaintTreeWalk;
ALWAYS_INLINE IntRect ComputeVisualRect(const LayoutObject&,
+ const NGPrePaintInfo*,
const PaintInvalidatorContext&);
ALWAYS_INLINE void UpdatePaintingLayer(const LayoutObject&,
- PaintInvalidatorContext&);
+ PaintInvalidatorContext&,
+ bool is_ng_painting);
ALWAYS_INLINE void UpdatePaintInvalidationContainer(const LayoutObject&,
- PaintInvalidatorContext&);
+ PaintInvalidatorContext&,
+ bool is_ng_painting);
ALWAYS_INLINE void UpdateEmptyVisualRectFlag(const LayoutObject&,
PaintInvalidatorContext&);
ALWAYS_INLINE void UpdateVisualRect(const LayoutObject&,
+ const NGPrePaintInfo*,
FragmentData&,
PaintInvalidatorContext&);
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
index b480f2e1c35..0d52eb19e02 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -77,6 +77,7 @@
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
@@ -92,6 +93,7 @@
#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
@@ -138,7 +140,7 @@ PaintLayerRareData::PaintLayerRareData()
PaintLayerRareData::~PaintLayerRareData() = default;
PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
- : is_root_layer_(layout_object.IsLayoutView()),
+ : is_root_layer_(IsA<LayoutView>(layout_object)),
has_visible_content_(false),
needs_descendant_dependent_flags_update_(true),
needs_visual_overflow_recalc_(true),
@@ -161,7 +163,6 @@ PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
previous_paint_result_(kFullyPainted),
needs_paint_phase_descendant_outlines_(false),
needs_paint_phase_float_(false),
- needs_paint_phase_descendant_block_backgrounds_(false),
has_descendant_with_clip_path_(false),
has_non_isolated_descendant_with_blend_mode_(false),
has_fixed_position_descendant_(false),
@@ -307,12 +308,9 @@ PhysicalOffset PaintLayer::SubpixelAccumulation() const {
}
void PaintLayer::SetSubpixelAccumulation(const PhysicalOffset& accumulation) {
- if (rare_data_ || !accumulation.IsZero()) {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+ if (rare_data_ || !accumulation.IsZero())
EnsureRareData().subpixel_accumulation = accumulation;
- if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) {
- scrollable_area->PositionOverflowControls();
- }
- }
}
void PaintLayer::UpdateLayerPositionsAfterLayout() {
@@ -411,7 +409,7 @@ void PaintLayer::UpdateTransformationMatrix() {
ComputedStyle::kIncludeIndependentTransformProperties);
MakeMatrixRenderable(
*transform,
- Compositor() ? Compositor()->HasAcceleratedCompositing() : false);
+ box->GetDocument().GetSettings()->GetAcceleratedCompositingEnabled());
}
}
@@ -690,8 +688,16 @@ void PaintLayer::UpdateDescendantDependentFlags() {
UpdateStackingNode();
if (old_has_non_isolated_descendant_with_blend_mode !=
- static_cast<bool>(has_non_isolated_descendant_with_blend_mode_))
+ static_cast<bool>(has_non_isolated_descendant_with_blend_mode_)) {
+ // The LayoutView DisplayItemClient owns painting of the background
+ // of the HTML element. When blending isolation of the HTML element's
+ // descendants change, there will be an addition or removal of an
+ // isolation effect node for the HTML element to add (or remove)
+ // isolated blending, and that case we need to re-paint the LayoutView.
+ if (Parent() && Parent()->IsRootLayer())
+ GetLayoutObject().View()->SetBackgroundNeedsFullPaintInvalidation();
GetLayoutObject().SetNeedsPaintPropertyUpdate();
+ }
needs_descendant_dependent_flags_update_ = false;
if (IsSelfPaintingLayer() && needs_visual_overflow_recalc_) {
@@ -859,19 +865,6 @@ void PaintLayer::UpdateSizeAndScrollingAfterLayout() {
}
}
-TransformationMatrix PaintLayer::PerspectiveTransform() const {
- if (!GetLayoutObject().HasTransformRelatedProperty())
- return TransformationMatrix();
-
- const ComputedStyle& style = GetLayoutObject().StyleRef();
- if (!style.HasPerspective())
- return TransformationMatrix();
-
- TransformationMatrix t;
- t.ApplyPerspective(style.Perspective());
- return t;
-}
-
FloatPoint PaintLayer::PerspectiveOrigin() const {
if (!GetLayoutObject().HasTransformRelatedProperty())
return FloatPoint();
@@ -1027,14 +1020,15 @@ PaintLayer* PaintLayer::EnclosingLayerForPaintInvalidation() const {
return nullptr;
}
-void PaintLayer::SetNeedsCompositingInputsUpdate() {
+void PaintLayer::SetNeedsCompositingInputsUpdate(bool mark_ancestor_flags) {
SetNeedsCompositingInputsUpdateInternal();
// TODO(chrishtr): These are a bit of a heavy hammer, because not all
// things which require compositing inputs update require a descendant-
// dependent flags update. Reduce call sites after CAP launch allows
/// removal of CompositingInputsUpdater.
- MarkAncestorChainForFlagsUpdate(NeedsDescendantDependentUpdate);
+ if (mark_ancestor_flags)
+ MarkAncestorChainForFlagsUpdate(NeedsDescendantDependentUpdate);
}
void PaintLayer::SetNeedsVisualOverflowRecalc() {
@@ -1083,6 +1077,8 @@ void PaintLayer::SetNeedsCompositingInputsUpdateInternal() {
last_ancestor = current;
current->child_needs_compositing_inputs_update_ = true;
if (Compositor() &&
+ (current != initial_layer ||
+ !current->GetLayoutObject().IsStickyPositioned()) &&
current->GetLayoutObject().ShouldApplyStrictContainment())
break;
}
@@ -1175,106 +1171,6 @@ bool PaintLayer::HasAncestorWithFilterThatMovesPixels() const {
return false;
}
-static void ExpandClipRectForDescendants(
- PhysicalRect& clip_rect,
- const PaintLayer* layer,
- const PaintLayer* root_layer,
- PaintLayer::TransparencyClipBoxBehavior transparency_behavior,
- const PhysicalOffset& sub_pixel_accumulation,
- GlobalPaintFlags global_paint_flags) {
- // If we have a mask, then the clip is limited to the border box area (and
- // there is no need to examine child layers).
- if (!layer->GetLayoutObject().HasMask()) {
- // Note: we don't have to walk z-order lists since transparent elements
- // always establish a stacking container. This means we can just walk the
- // layer tree directly.
- for (PaintLayer* curr = layer->FirstChild(); curr;
- curr = curr->NextSibling())
- clip_rect.Unite(PaintLayer::TransparencyClipBox(
- curr, root_layer, transparency_behavior,
- PaintLayer::kDescendantsOfTransparencyClipBox, sub_pixel_accumulation,
- global_paint_flags));
- }
-}
-
-PhysicalRect PaintLayer::TransparencyClipBox(
- const PaintLayer* layer,
- const PaintLayer* root_layer,
- TransparencyClipBoxBehavior transparency_behavior,
- TransparencyClipBoxMode transparency_mode,
- const PhysicalOffset& sub_pixel_accumulation,
- GlobalPaintFlags global_paint_flags) {
- // FIXME: Although this function completely ignores CSS-imposed clipping, we
- // did already intersect with the paintDirtyRect, and that should cut down on
- // the amount we have to paint. Still it would be better to respect clips.
-
- if (root_layer != layer &&
- ((transparency_behavior == kPaintingTransparencyClipBox &&
- layer->PaintsWithTransform(global_paint_flags)) ||
- (transparency_behavior == kHitTestingTransparencyClipBox &&
- layer->HasTransformRelatedProperty()))) {
- // The best we can do here is to use enclosed bounding boxes to establish a
- // "fuzzy" enough clip to encompass the transformed layer and all of its
- // children.
- const PaintLayer* pagination_layer =
- transparency_mode == kDescendantsOfTransparencyClipBox
- ? layer->EnclosingPaginationLayer()
- : nullptr;
- const PaintLayer* root_layer_for_transform =
- pagination_layer ? pagination_layer : root_layer;
- PhysicalOffset delta;
- layer->ConvertToLayerCoords(root_layer_for_transform, delta);
-
- delta += sub_pixel_accumulation;
- IntPoint pixel_snapped_delta = RoundedIntPoint(delta);
- TransformationMatrix transform;
- transform.Translate(pixel_snapped_delta.X(), pixel_snapped_delta.Y());
- if (layer->Transform())
- transform = transform * *layer->Transform();
-
- // We don't use fragment boxes when collecting a transformed layer's
- // bounding box, since it always paints unfragmented.
- PhysicalRect clip_rect = layer->LocalBoundingBox();
- ExpandClipRectForDescendants(clip_rect, layer, layer, transparency_behavior,
- sub_pixel_accumulation, global_paint_flags);
- PhysicalRect result = PhysicalRect::EnclosingRect(
- transform.MapRect(layer->MapRectForFilter(FloatRect(clip_rect))));
- if (!pagination_layer)
- return result;
-
- // We have to break up the transformed extent across our columns.
- // Split our box up into the actual fragment boxes that layout in the
- // columns/pages and unite those together to get our true bounding box.
- LayoutFlowThread& enclosing_flow_thread =
- ToLayoutFlowThread(pagination_layer->GetLayoutObject());
- result = PhysicalRectToBeNoop(
- enclosing_flow_thread.FragmentsBoundingBox(result.ToLayoutRect()));
-
- PhysicalOffset root_layer_delta;
- pagination_layer->ConvertToLayerCoords(root_layer, root_layer_delta);
- result.Move(root_layer_delta);
- return result;
- }
-
- PhysicalRect clip_rect = layer->ShouldFragmentCompositedBounds(root_layer)
- ? layer->FragmentsBoundingBox(root_layer)
- : layer->PhysicalBoundingBox(root_layer);
- ExpandClipRectForDescendants(clip_rect, layer, root_layer,
- transparency_behavior, sub_pixel_accumulation,
- global_paint_flags);
-
- // Convert clipRect into local coordinates for mapLayerRectForFilter(), and
- // convert back after.
- PhysicalOffset delta;
- layer->ConvertToLayerCoords(root_layer, delta);
- clip_rect.Move(-delta);
- clip_rect = layer->MapRectForFilter(clip_rect);
- clip_rect.Move(delta);
-
- clip_rect.Move(sub_pixel_accumulation);
- return clip_rect;
-}
-
void* PaintLayer::operator new(size_t sz) {
return WTF::Partitions::LayoutPartition()->Alloc(
sz, WTF_HEAP_PROFILER_TYPE_NAME(PaintLayer));
@@ -1367,6 +1263,9 @@ void PaintLayer::RemoveChild(PaintLayer* old_child) {
if (Compositor()) {
if (!old_child_style.IsStacked())
Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
+
+ if (Compositor()->GetCompositingInputsRoot() == old_child)
+ Compositor()->ClearCompositingInputsRoot();
}
// Dirty the z-order list in which we are contained.
old_child->DirtyStackingContextZOrderLists();
@@ -1475,7 +1374,7 @@ void PaintLayer::InsertOnlyThisLayerAfterStyleChange() {
// and its descendants to change paint invalidation container.
bool did_set_paint_invalidation = false;
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- !GetLayoutObject().IsLayoutView() && GetLayoutObject().IsRooted() &&
+ !IsA<LayoutView>(GetLayoutObject()) && GetLayoutObject().IsRooted() &&
GetLayoutObject().StyleRef().IsStacked()) {
const LayoutBoxModelObject& previous_paint_invalidation_container =
GetLayoutObject().Parent()->ContainerForPaintInvalidation();
@@ -1639,16 +1538,20 @@ bool PaintLayer::RequiresScrollableArea() const {
void PaintLayer::UpdateScrollableArea() {
if (RequiresScrollableArea() && !scrollable_area_) {
- scrollable_area_ = PaintLayerScrollableArea::Create(*this);
+ scrollable_area_ = MakeGarbageCollected<PaintLayerScrollableArea>(*this);
if (Compositor()) {
Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
}
+ GetLayoutObject().SetNeedsPaintPropertyUpdate();
} else if (!RequiresScrollableArea() && scrollable_area_) {
scrollable_area_->Dispose();
scrollable_area_.Clear();
if (Compositor()) {
Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
}
+ GetLayoutObject().SetBackgroundPaintLocation(
+ kBackgroundPaintInGraphicsLayer);
+ GetLayoutObject().SetNeedsPaintPropertyUpdate();
}
}
@@ -1787,6 +1690,16 @@ void PaintLayer::CollectFragments(
fragment.root_fragment_data = root_fragment_data;
fragment.fragment_data = fragment_data;
+ if (GetLayoutObject().CanTraversePhysicalFragments()) {
+ if (const auto* block = DynamicTo<LayoutBlock>(&GetLayoutObject())) {
+ fragment.physical_fragment = block->CurrentFragment();
+ DCHECK(fragment.physical_fragment);
+
+ // TODO(mstensho): Implement support for multiple fragments per node.
+ DCHECK(!fragment_data->NextFragment());
+ }
+ }
+
fragments.push_back(fragment);
}
}
@@ -2052,7 +1965,7 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
// The natural thing would be to keep HitTestingTransformState on the stack,
// but it's big, so we heap-allocate.
HitTestingTransformState* local_transform_state = nullptr;
- base::Optional<HitTestingTransformState> storage;
+ STACK_UNINITIALIZED base::Optional<HitTestingTransformState> storage;
if (applied_transform) {
// We computed the correct state in the caller (above code), so just
@@ -2071,7 +1984,7 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
// Check for hit test on backface if backface-visibility is 'hidden'
if (local_transform_state && layout_object.StyleRef().BackfaceVisibility() ==
EBackfaceVisibility::kHidden) {
- TransformationMatrix inverted_matrix =
+ STACK_UNINITIALIZED TransformationMatrix inverted_matrix =
local_transform_state->accumulated_transform_.Inverse();
// If the z-vector of the matrix is negative, the back is facing towards the
// viewer.
@@ -2080,7 +1993,8 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
}
HitTestingTransformState* unflattened_transform_state = local_transform_state;
- base::Optional<HitTestingTransformState> unflattened_storage;
+ STACK_UNINITIALIZED base::Optional<HitTestingTransformState>
+ unflattened_storage;
if (local_transform_state && !Preserves3D()) {
// Keep a copy of the pre-flattening state, for computing z-offsets for the
// container
@@ -2111,7 +2025,7 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
// Collect the fragments. This will compute the clip rectangles for each
// layer fragment.
- base::Optional<PaintLayerFragments> layer_fragments;
+ STACK_UNINITIALIZED base::Optional<PaintLayerFragments> layer_fragments;
if (recursion_data.intersects_location) {
layer_fragments.emplace();
if (applied_transform) {
@@ -2189,8 +2103,8 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
DisplayLockLifecycleTarget::kChildren)) {
// Hit test with a temporary HitTestResult, because we only want to commit
// to 'result' if we know we're frontmost.
- HitTestResult temp_result(result.GetHitTestRequest(),
- recursion_data.original_location);
+ STACK_UNINITIALIZED HitTestResult temp_result(
+ result.GetHitTestRequest(), recursion_data.original_location);
temp_result.SetInertNode(result.InertNode());
bool inside_fragment_foreground_rect = false;
@@ -2237,8 +2151,8 @@ PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
return candidate_layer;
if (recursion_data.intersects_location && IsSelfPaintingLayer()) {
- HitTestResult temp_result(result.GetHitTestRequest(),
- recursion_data.original_location);
+ STACK_UNINITIALIZED HitTestResult temp_result(
+ result.GetHitTestRequest(), recursion_data.original_location);
temp_result.SetInertNode(result.InertNode());
bool inside_fragment_background_rect = false;
if (HitTestContentsForFragments(*layer_fragments, offset, temp_result,
@@ -2286,8 +2200,8 @@ bool PaintLayer::HitTestContentsForFragments(
inside_clip_rect = true;
PhysicalOffset fragment_offset = offset;
fragment_offset += fragment.layer_bounds.offset;
- if (HitTestContents(result, fragment_offset, hit_test_location,
- hit_test_filter))
+ if (HitTestContents(result, fragment.physical_fragment, fragment_offset,
+ hit_test_location, hit_test_filter))
return true;
}
@@ -2321,7 +2235,7 @@ PaintLayer* PaintLayer::HitTestTransformedLayerInFragments(
PaintLayer* hit_layer = HitTestLayerByApplyingTransform(
root_layer, container_layer, result, recursion_data, transform_state,
z_offset, check_resizer_only,
- fragment.fragment_data->PaginationOffset());
+ fragment.fragment_data->LegacyPaginationOffset());
if (hit_layer)
return hit_layer;
}
@@ -2370,12 +2284,23 @@ PaintLayer* PaintLayer::HitTestLayerByApplyingTransform(
}
bool PaintLayer::HitTestContents(HitTestResult& result,
+ const NGPhysicalBoxFragment* physical_fragment,
const PhysicalOffset& fragment_offset,
const HitTestLocation& hit_test_location,
HitTestFilter hit_test_filter) const {
DCHECK(IsSelfPaintingLayer() || HasSelfPaintingLayerDescendant());
- if (!GetLayoutObject().HitTestAllPhases(result, hit_test_location,
- fragment_offset, hit_test_filter)) {
+
+ bool did_hit;
+ if (physical_fragment) {
+ did_hit = NGBoxFragmentPainter(*physical_fragment)
+ .HitTestAllPhases(result, hit_test_location, fragment_offset,
+ hit_test_filter);
+ } else {
+ did_hit = GetLayoutObject().HitTestAllPhases(
+ result, hit_test_location, fragment_offset, hit_test_filter);
+ }
+
+ if (!did_hit) {
// It's wrong to set innerNode, but then claim that you didn't hit anything,
// unless it is a list-based test.
DCHECK(!result.InnerNode() || (result.GetHitTestRequest().ListBased() &&
@@ -2469,8 +2394,8 @@ PaintLayer* PaintLayer::HitTestChildren(
}
PaintLayer* hit_layer = nullptr;
- HitTestResult temp_result(result.GetHitTestRequest(),
- recursion_data.original_location);
+ STACK_UNINITIALIZED HitTestResult temp_result(
+ result.GetHitTestRequest(), recursion_data.original_location);
temp_result.SetInertNode(result.InertNode());
hit_layer = child_layer->HitTestLayer(
root_layer, this, temp_result, recursion_data, false, transform_state,
@@ -2497,7 +2422,7 @@ PaintLayer* PaintLayer::HitTestChildren(
}
void PaintLayer::UpdateFilterReferenceBox() {
- if (!NeedsFilterReferenceBox())
+ if (!HasFilterThatMovesPixels())
return;
FloatRect reference_box =
FloatRect(PhysicalBoundingBoxIncludingStackingChildren(
@@ -2511,16 +2436,6 @@ void PaintLayer::UpdateFilterReferenceBox() {
EnsureResourceInfo().SetFilterReferenceBox(reference_box);
}
-bool PaintLayer::NeedsFilterReferenceBox() const {
- if (GetLayoutObject().HasReflection() && GetLayoutObject().IsBox())
- return true;
- FilterOperations operations = GetLayoutObject().StyleRef().Filter();
- if (operations.HasBlurOrReferenceFilter())
- return true;
- operations = GetLayoutObject().StyleRef().BackdropFilter();
- return !operations.IsEmpty();
-}
-
FloatRect PaintLayer::FilterReferenceBox() const {
DCHECK(IsAllowedToQueryCompositingState());
if (ResourceInfo())
@@ -2571,13 +2486,9 @@ bool PaintLayer::HitTestClippedOutByClipPath(
return !clip_path->GetPath(reference_box).Contains(point);
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
- SVGResource* resource =
- To<ReferenceClipPathOperation>(*clip_path_operation).Resource();
- LayoutSVGResourceContainer* container =
- resource ? resource->ResourceContainer() : nullptr;
- if (!container || container->ResourceType() != kClipperResourceType)
+ LayoutSVGResourceClipper* clipper = GetSVGResourceAsType(clip_path_operation);
+ if (!clipper)
return false;
- auto* clipper = ToLayoutSVGResourceClipper(container);
// If the clipPath is using "userspace on use" units, then the origin of
// the coordinate system is the top-left of the reference box, so adjust
// the point accordingly.
@@ -2678,6 +2589,14 @@ void PaintLayer::ExpandRectForStackingChildren(
const PaintLayer& composited_layer,
PhysicalRect& result,
PaintLayer::CalculateBoundsOptions options) const {
+ // If we're locked, th en the subtree does not contribute painted output.
+ // Furthermore, we might not have up-to-date sizing and position information
+ // in the subtree, so skip recursing into the subtree.
+ if (GetLayoutObject().PaintBlockedByDisplayLock(
+ DisplayLockLifecycleTarget::kChildren)) {
+ return;
+ }
+
PaintLayerPaintOrderIterator iterator(*this, kAllChildren);
while (PaintLayer* child_layer = iterator.Next()) {
// Here we exclude both directly composited layers and squashing layers
@@ -2928,6 +2847,12 @@ bool PaintLayer::SupportsSubsequenceCaching() const {
if (GetLayoutObject().IsSVGRoot())
return true;
+ // Don't create subsequence for the document element because the subsequence
+ // for LayoutView serves the same purpose. This can avoid unnecessary paint
+ // chunks that would otherwise be forced by the subsequence.
+ if (GetLayoutObject().IsDocumentElement())
+ return false;
+
// Create subsequence for only stacking contexts whose painting are atomic.
return GetLayoutObject().StyleRef().IsStackingContext();
}
@@ -3438,7 +3363,7 @@ bool PaintLayer::HasFilterThatMovesPixels() const {
const ComputedStyle& style = GetLayoutObject().StyleRef();
if (style.HasFilter() && style.Filter().HasFilterThatMovesPixels())
return true;
- if (style.HasBoxReflect())
+ if (GetLayoutObject().HasReflection())
return true;
return false;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer.h b/chromium/third_party/blink/renderer/core/paint/paint_layer.h
index 29b9f163f4a..98a46602c6d 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer.h
@@ -315,6 +315,9 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
// FIXME: size() should DCHECK(!needs_position_update_) as well, but that
// fails in some tests, for example, fast/repaint/clipped-relative.html.
const LayoutSize& Size() const { return size_; }
+ // TODO(crbug.com/962299): This method snaps to pixels incorrectly because
+ // Location() is not the correct paint offset. It's also incorrect in flipped
+ // blocks writing mode.
IntSize PixelSnappedSize() const {
LayoutPoint location = layout_object_.IsBox()
? ToLayoutBox(layout_object_).Location()
@@ -506,10 +509,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
TransformationMatrix CurrentTransform() const;
TransformationMatrix RenderableTransform(GlobalPaintFlags) const;
- // Get the perspective transform, which is applied to transformed sublayers.
- // Returns true if the layer has a -webkit-perspective.
- // Note that this transform does not have the perspective-origin baked in.
- TransformationMatrix PerspectiveTransform() const;
FloatPoint PerspectiveOrigin() const;
bool Preserves3D() const {
return GetLayoutObject().StyleRef().Preserves3D();
@@ -793,8 +792,11 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
bool is_under_position_sticky = false;
};
+ bool NeedsVisualOverflowRecalc() const {
+ return needs_visual_overflow_recalc_;
+ }
void SetNeedsVisualOverflowRecalc();
- void SetNeedsCompositingInputsUpdate();
+ void SetNeedsCompositingInputsUpdate(bool mark_ancestor_flags = true);
// This methods marks everything from this layer up to the |ancestor| argument
// (both included).
@@ -975,24 +977,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const PhysicalOffset* offset_from_root = nullptr,
const PhysicalOffset& sub_pixel_accumulation = PhysicalOffset()) const;
- enum TransparencyClipBoxBehavior {
- kPaintingTransparencyClipBox,
- kHitTestingTransparencyClipBox
- };
-
- enum TransparencyClipBoxMode {
- kDescendantsOfTransparencyClipBox,
- kRootOfTransparencyClipBox
- };
-
- static PhysicalRect TransparencyClipBox(
- const PaintLayer*,
- const PaintLayer* root_layer,
- TransparencyClipBoxBehavior transparency_behavior,
- TransparencyClipBoxMode transparency_mode,
- const PhysicalOffset& sub_pixel_accumulation,
- GlobalPaintFlags = kGlobalPaintNormalPhase);
-
bool SelfNeedsRepaint() const { return self_needs_repaint_; }
bool DescendantNeedsRepaint() const { return descendant_needs_repaint_; }
bool SelfOrDescendantNeedsRepaint() const {
@@ -1037,15 +1021,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
needs_paint_phase_float_ = true;
}
- // Similar to above, but for PaintPhaseDescendantBlockBackgroundsOnly.
- bool NeedsPaintPhaseDescendantBlockBackgrounds() const {
- return needs_paint_phase_descendant_block_backgrounds_;
- }
- void SetNeedsPaintPhaseDescendantBlockBackgrounds() {
- DCHECK(IsSelfPaintingLayer());
- needs_paint_phase_descendant_block_backgrounds_ = true;
- }
-
bool DescendantHasDirectOrScrollingCompositingReason() const {
return descendant_has_direct_or_scrolling_compositing_reason_;
}
@@ -1123,10 +1098,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
void DirtyStackingContextZOrderLists();
- bool NeedsVisualOverflowRecalcForTesting() const {
- return needs_visual_overflow_recalc_;
- }
-
PhysicalOffset OffsetForInFlowRelPosition() const {
return rare_data_ ? rare_data_->offset_for_in_flow_rel_position
: PhysicalOffset();
@@ -1198,6 +1169,7 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
const PhysicalOffset& translation_offset = PhysicalOffset()) const;
bool HitTestContents(HitTestResult&,
+ const NGPhysicalBoxFragment*,
const PhysicalOffset& fragment_offset,
const HitTestLocation&,
HitTestFilter) const;
@@ -1264,8 +1236,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
needs_paint_phase_descendant_outlines_ |=
layer.needs_paint_phase_descendant_outlines_;
needs_paint_phase_float_ |= layer.needs_paint_phase_float_;
- needs_paint_phase_descendant_block_backgrounds_ |=
- layer.needs_paint_phase_descendant_block_backgrounds_;
}
void ExpandRectForStackingChildren(const PaintLayer& composited_layer,
@@ -1281,8 +1251,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
bool ShouldApplyTransformToBoundingBox(const PaintLayer& composited_layer,
CalculateBoundsOptions) const;
- bool NeedsFilterReferenceBox() const;
-
AncestorDependentCompositingInputs& EnsureAncestorDependentCompositingInputs()
const {
if (!ancestor_dependent_compositing_inputs_) {
@@ -1347,7 +1315,6 @@ class CORE_EXPORT PaintLayer : public DisplayItemClient {
unsigned needs_paint_phase_descendant_outlines_ : 1;
unsigned needs_paint_phase_float_ : 1;
- unsigned needs_paint_phase_descendant_block_backgrounds_ : 1;
// These bitfields are part of ancestor/descendant dependent compositing
// inputs.
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc
index 661c7c33a8b..6aaa19c0b1d 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_clipper_test.cc
@@ -183,21 +183,12 @@ TEST_F(PaintLayerClipperTest, ControlClip) {
.CalculateRects(context,
&target_paint_layer->GetLayoutObject().FirstFragment(),
nullptr, layer_bounds, background_rect, foreground_rect);
-#if defined(OS_MACOSX)
- // If the PaintLayer clips overflow, the background rect is intersected with
- // the PaintLayer bounds...
- EXPECT_EQ(PhysicalRect(3, 4, 210, 28), background_rect.Rect());
- // and the foreground rect is intersected with the control clip in this case.
- EXPECT_EQ(PhysicalRect(8, 8, 200, 18), foreground_rect.Rect());
- EXPECT_EQ(PhysicalRect(8, 8, 200, 18), layer_bounds);
-#else
// If the PaintLayer clips overflow, the background rect is intersected with
// the PaintLayer bounds...
EXPECT_EQ(PhysicalRect(8, 8, 200, 300), background_rect.Rect());
// and the foreground rect is intersected with the control clip in this case.
EXPECT_EQ(PhysicalRect(10, 10, 196, 296), foreground_rect.Rect());
EXPECT_EQ(PhysicalRect(8, 8, 200, 300), layer_bounds);
-#endif
}
TEST_F(PaintLayerClipperTest, RoundedClip) {
@@ -302,8 +293,8 @@ TEST_F(PaintLayerClipperTest, ControlClipSelect) {
PhysicalRect content_box_rect = target->PhysicalContentBoxRect();
EXPECT_GT(foreground_rect.Rect().X(),
content_box_rect.X() + target->Location().X());
- EXPECT_LT(foreground_rect.Rect().Width(), content_box_rect.Width());
-} // namespace blink
+ EXPECT_LE(foreground_rect.Rect().Width(), content_box_rect.Width());
+}
TEST_F(PaintLayerClipperTest, LayoutSVGRootChild) {
SetBodyInnerHTML(R"HTML(
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_fragment.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_fragment.h
index 6b0d2e3a7d7..9ffa07ab179 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_fragment.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_fragment.h
@@ -33,6 +33,7 @@
namespace blink {
class FragmentData;
+class NGPhysicalBoxFragment;
// PaintLayerFragment is the representation of a fragment.
// https://drafts.csswg.org/css-break/#fragment
@@ -84,6 +85,8 @@ struct PaintLayerFragment {
// The corresponding FragmentData of this structure.
const FragmentData* fragment_data = nullptr;
+
+ const NGPhysicalBoxFragment* physical_fragment = nullptr;
};
typedef Vector<PaintLayerFragment, 1> PaintLayerFragments;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 7e1b0ab4992..9017869339e 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -7,21 +7,24 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
#include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
#include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_display_item_fragment.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
+#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_hint.h"
#include "third_party/blink/renderer/platform/graphics/paint/subsequence_recorder.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -46,8 +49,6 @@ static ShouldRespectOverflowClipType ShouldRespectOverflowClip(
}
bool PaintLayerPainter::PaintedOutputInvisible(const ComputedStyle& style) {
- DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-
if (style.HasBackdropFilter())
return false;
@@ -75,19 +76,16 @@ PaintResult PaintLayerPainter::Paint(
if (paint_layer_.GetLayoutObject().GetFrameView()->ShouldThrottleRendering())
return kFullyPainted;
- // https://code.google.com/p/chromium/issues/detail?id=343772
- DisableCompositingQueryAsserts disabler;
-
// Non self-painting layers without self-painting descendants don't need to be
// painted as their layoutObject() should properly paint itself.
if (!paint_layer_.IsSelfPaintingLayer() &&
!paint_layer_.HasSelfPaintingLayerDescendant())
return kFullyPainted;
- // If this layer is totally invisible then there is nothing to paint. In CAP
- // we simplify this optimization by painting even when effectively invisible
- // but skipping the painted content during layerization in
- // PaintArtifactCompositor.
+ // If this layer is totally invisible then there is nothing to paint.
+ // In CompositeAfterPaint we simplify this optimization by painting even when
+ // effectively invisible but skipping the painted content during layerization
+ // in PaintArtifactCompositor.
if (paint_layer_.PaintsWithTransparency(
painting_info.GetGlobalPaintFlags())) {
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
@@ -108,10 +106,10 @@ PaintResult PaintLayerPainter::Paint(
return PaintLayerContents(context, painting_info, paint_flags);
}
-static bool ShouldCreateSubsequence(const PaintLayer& paint_layer,
- const GraphicsContext& context,
- const PaintLayerPaintingInfo& painting_info,
- PaintLayerFlags paint_flags) {
+static bool ShouldCreateSubsequence(
+ const PaintLayer& paint_layer,
+ const GraphicsContext& context,
+ const PaintLayerPaintingInfo& painting_info) {
// Caching is not needed during printing or painting previews.
if (context.Printing() || context.IsPaintingPreview())
return false;
@@ -127,7 +125,8 @@ static bool ShouldCreateSubsequence(const PaintLayer& paint_layer,
// CachedDisplayItemList. This also avoids conflict of
// PaintLayer::previousXXX() when paintLayer is composited scrolling and is
// painted twice for GraphicsLayers of container and scrolling contents.
- if (paint_layer.GetCompositingState() == kPaintsIntoOwnBacking)
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ paint_layer.GetCompositingState() == kPaintsIntoOwnBacking)
return false;
// Don't create subsequence during special painting to avoid cache conflict
@@ -136,9 +135,6 @@ static bool ShouldCreateSubsequence(const PaintLayer& paint_layer,
kGlobalPaintFlattenCompositingLayers)
return false;
- if (paint_flags & kPaintLayerPaintingOverlayOverflowControls)
- return false;
-
return true;
}
@@ -196,7 +192,7 @@ static bool IsMainFrameNotClippingContents(const PaintLayer& layer) {
// If MainFrameClipsContent is false which means that WebPreferences::
// record_whole_document is true, we should not cull the scrolling contents
// of the main frame.
- if (layer.GetLayoutObject().IsLayoutView()) {
+ if (IsA<LayoutView>(layer.GetLayoutObject())) {
const auto* frame = layer.GetLayoutObject().GetFrame();
if (frame && frame->IsMainFrame() && !frame->ClipsContent())
return true;
@@ -326,6 +322,15 @@ PaintResult PaintLayerPainter::PaintLayerContents(
return kMayBeClippedByCullRect;
}
+ bool selection_drag_image_only = painting_info_arg.GetGlobalPaintFlags() &
+ kGlobalPaintSelectionDragImageOnly;
+ if (selection_drag_image_only && !paint_layer_.GetLayoutObject().IsSelected())
+ return result;
+
+ base::Optional<IgnorePaintTimingScope> ignore_paint_timing;
+ if (PaintedOutputInvisible(paint_layer_.GetLayoutObject().StyleRef()))
+ ignore_paint_timing.emplace();
+
PaintLayerFlags paint_flags = paint_flags_arg;
PaintLayerPaintingInfo painting_info = painting_info_arg;
AdjustForPaintProperties(context, painting_info, paint_flags);
@@ -355,15 +360,25 @@ PaintResult PaintLayerPainter::PaintLayerContents(
paint_layer_.GetLayoutObject().StyleRef().HasOutline();
PhysicalOffset subpixel_accumulation =
- paint_layer_.GetCompositingState() == kPaintsIntoOwnBacking
+ (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+ paint_layer_.GetCompositingState() == kPaintsIntoOwnBacking)
? paint_layer_.SubpixelAccumulation()
: painting_info.sub_pixel_accumulation;
ShouldRespectOverflowClipType respect_overflow_clip =
ShouldRespectOverflowClip(paint_flags, paint_layer_.GetLayoutObject());
- bool should_create_subsequence = ShouldCreateSubsequence(
- paint_layer_, context, painting_info, paint_flags);
+ bool should_paint_content =
+ paint_layer_.HasVisibleContent() &&
+ // Content under a LayoutSVGHiddenContainer is auxiliary resources for
+ // painting. Foreign content should never paint in this situation, as it
+ // is primary, not auxiliary.
+ !paint_layer_.IsUnderSVGHiddenContainer() && is_self_painting_layer &&
+ !is_painting_overlay_overflow_controls;
+
+ bool should_create_subsequence =
+ should_paint_content &&
+ ShouldCreateSubsequence(paint_layer_, context, painting_info);
base::Optional<SubsequenceRecorder> subsequence_recorder;
if (should_create_subsequence) {
@@ -397,20 +412,13 @@ PaintResult PaintLayerPainter::PaintLayerContents(
subpixel_accumulation)
: offset_from_root;
clip_path_clipper.emplace(context, paint_layer_.GetLayoutObject(),
+ paint_layer_.GetLayoutObject(),
visual_offset_from_root);
}
PaintLayerPaintingInfo local_painting_info(painting_info);
local_painting_info.sub_pixel_accumulation = subpixel_accumulation;
- bool should_paint_content =
- paint_layer_.HasVisibleContent() &&
- // Content under a LayoutSVGHiddenContainer is auxiliary resources for
- // painting. Foreign content should never paint in this situation, as it
- // is primary, not auxiliary.
- !paint_layer_.IsUnderSVGHiddenContainer() && is_self_painting_layer &&
- !is_painting_overlay_overflow_controls;
-
PaintLayerFragments layer_fragments;
if (should_paint_content || should_paint_self_outline ||
@@ -437,16 +445,10 @@ PaintResult PaintLayerPainter::PaintLayerContents(
}
}
- bool selection_only =
- local_painting_info.GetGlobalPaintFlags() & kGlobalPaintSelectionOnly;
-
{ // Begin block for the lifetime of any filter.
- size_t display_item_list_size_before_painting =
- context.GetPaintController().NewDisplayItemList().size();
-
bool is_painting_root_layer = (&paint_layer_) == painting_info.root_layer;
bool should_paint_background =
- should_paint_content && !selection_only &&
+ should_paint_content && !selection_drag_image_only &&
(is_painting_composited_background ||
(is_painting_root_layer &&
!(paint_flags & kPaintLayerPaintingSkipRootBackground)));
@@ -459,46 +461,45 @@ PaintResult PaintLayerPainter::PaintLayerContents(
bool should_paint_normal_flow_and_pos_z_order_lists =
is_painting_composited_foreground &&
!is_painting_overlay_overflow_controls;
- bool is_video = paint_layer_.GetLayoutObject().IsVideo();
-
- base::Optional<ScopedPaintChunkProperties>
- subsequence_forced_chunk_properties;
- if (subsequence_recorder && paint_layer_.HasSelfPaintingLayerDescendant()) {
- // Prepare for forced paint chunks to ensure chunk id stability to avoid
- // unnecessary full chunk raster invalidations on changed chunk ids.
- // TODO(crbug.com/834606): This may be unnecessary after we refactor
- // raster invalidation not to depend on chunk ids too much.
- subsequence_forced_chunk_properties.emplace(
- context.GetPaintController(),
- paint_layer_.GetLayoutObject()
- .FirstFragment()
- .LocalBorderBoxProperties(),
- paint_layer_, DisplayItem::kUninitializedType);
+ bool is_video = IsA<LayoutVideo>(paint_layer_.GetLayoutObject());
+
+ base::Optional<ScopedPaintChunkHint> paint_chunk_hint;
+ if (should_paint_content) {
+ paint_chunk_hint.emplace(context.GetPaintController(),
+ paint_layer_.GetLayoutObject()
+ .FirstFragment()
+ .LocalBorderBoxProperties(),
+ paint_layer_, DisplayItem::kLayerChunk);
}
if (should_paint_background) {
- if (subsequence_forced_chunk_properties) {
- context.GetPaintController().ForceNewChunk(
- paint_layer_, DisplayItem::kLayerChunkBackground);
- }
PaintBackgroundForFragments(layer_fragments, context, local_painting_info,
paint_flags);
}
if (should_paint_neg_z_order_list) {
- if (subsequence_forced_chunk_properties) {
- context.GetPaintController().ForceNewChunk(
- paint_layer_, DisplayItem::kLayerChunkNegativeZOrderChildren);
- }
if (PaintChildren(kNegativeZOrderChildren, context, painting_info,
paint_flags) == kMayBeClippedByCullRect)
result = kMayBeClippedByCullRect;
}
if (should_paint_own_contents) {
- PaintForegroundForFragments(
- layer_fragments, context, local_painting_info, selection_only,
- !!subsequence_forced_chunk_properties, paint_flags);
+ base::Optional<ScopedPaintChunkHint> paint_chunk_hint_foreground;
+ if (paint_chunk_hint && paint_chunk_hint->HasCreatedPaintChunk()) {
+ // Hint a foreground chunk if we have created any chunks, to give the
+ // paint chunk after the previous forced paint chunks a stable id.
+ paint_chunk_hint_foreground.emplace(context.GetPaintController(),
+ paint_layer_,
+ DisplayItem::kLayerChunkForeground);
+ }
+ if (selection_drag_image_only) {
+ PaintForegroundForFragmentsWithPhase(PaintPhase::kSelectionDragImage,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
+ } else {
+ PaintForegroundForFragments(layer_fragments, context,
+ local_painting_info, paint_flags);
+ }
}
if (!is_video && should_paint_self_outline) {
@@ -507,11 +508,6 @@ PaintResult PaintLayerPainter::PaintLayerContents(
}
if (should_paint_normal_flow_and_pos_z_order_lists) {
- if (subsequence_forced_chunk_properties) {
- context.GetPaintController().ForceNewChunk(
- paint_layer_,
- DisplayItem::kLayerChunkNormalFlowAndPositiveZOrderChildren);
- }
if (PaintChildren(kNormalFlowAndPositiveZOrderChildren, context,
painting_info, paint_flags) == kMayBeClippedByCullRect)
result = kMayBeClippedByCullRect;
@@ -532,24 +528,11 @@ PaintResult PaintLayerPainter::PaintLayerContents(
PaintSelfOutlineForFragments(layer_fragments, context,
local_painting_info, paint_flags);
}
-
- if (!is_painting_overlay_overflow_controls) {
- // For filters, if the layer painted nothing, we need to issue a no-op
- // display item to ensure the filters won't be ignored. For backdrop
- // filters, we issue the display item regardless of other paintings to
- // ensure correct bounds of the composited layer for the backdrop filter.
- if ((paint_layer_.PaintsWithFilters() &&
- display_item_list_size_before_painting ==
- context.GetPaintController().NewDisplayItemList().size()) ||
- paint_layer_.GetLayoutObject().HasBackdropFilter()) {
- PaintEmptyContentForFilters(context);
- }
- }
} // FilterPainter block
bool should_paint_mask = is_painting_mask && should_paint_content &&
paint_layer_.GetLayoutObject().HasMask() &&
- !selection_only;
+ !selection_drag_image_only;
if (should_paint_mask) {
PaintMaskForFragments(layer_fragments, context, local_painting_info,
paint_flags);
@@ -739,7 +722,10 @@ void PaintLayerPainter::PaintFragmentWithPhase(
DisplayLockLifecycleTarget::kChildren))) {
paint_info.SetDescendantPaintingBlocked(true);
}
- paint_layer_.GetLayoutObject().Paint(paint_info);
+ if (fragment.physical_fragment)
+ NGBoxFragmentPainter(*fragment.physical_fragment).Paint(paint_info);
+ else
+ paint_layer_.GetLayoutObject().Paint(paint_info);
}
void PaintLayerPainter::PaintBackgroundForFragments(
@@ -759,57 +745,33 @@ void PaintLayerPainter::PaintForegroundForFragments(
const PaintLayerFragments& layer_fragments,
GraphicsContext& context,
const PaintLayerPaintingInfo& local_painting_info,
- bool selection_only,
- bool force_paint_chunks,
PaintLayerFlags paint_flags) {
- if (selection_only) {
- PaintForegroundForFragmentsWithPhase(PaintPhase::kSelection,
+ PaintForegroundForFragmentsWithPhase(
+ PaintPhase::kDescendantBlockBackgroundsOnly, layer_fragments, context,
+ local_painting_info, paint_flags);
+
+ if (paint_layer_.GetLayoutObject().GetDocument().InForcedColorsMode()) {
+ PaintForegroundForFragmentsWithPhase(PaintPhase::kForcedColorsModeBackplate,
layer_fragments, context,
local_painting_info, paint_flags);
- } else {
- if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
- paint_layer_.NeedsPaintPhaseDescendantBlockBackgrounds()) {
- if (force_paint_chunks) {
- context.GetPaintController().ForceNewChunk(
- paint_layer_, DisplayItem::kLayerChunkDescendantBackgrounds);
- }
- PaintForegroundForFragmentsWithPhase(
- PaintPhase::kDescendantBlockBackgroundsOnly, layer_fragments, context,
- local_painting_info, paint_flags);
- }
-
- if (paint_layer_.GetLayoutObject().GetDocument().InForcedColorsMode()) {
- PaintForegroundForFragmentsWithPhase(
- PaintPhase::kForcedColorsModeBackplate, layer_fragments, context,
- local_painting_info, paint_flags);
- }
+ }
- if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
- paint_layer_.NeedsPaintPhaseFloat()) {
- if (force_paint_chunks) {
- context.GetPaintController().ForceNewChunk(
- paint_layer_, DisplayItem::kLayerChunkFloat);
- }
- PaintForegroundForFragmentsWithPhase(PaintPhase::kFloat, layer_fragments,
- context, local_painting_info,
- paint_flags);
- }
+ if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
+ paint_layer_.NeedsPaintPhaseFloat()) {
+ PaintForegroundForFragmentsWithPhase(PaintPhase::kFloat, layer_fragments,
+ context, local_painting_info,
+ paint_flags);
+ }
- if (force_paint_chunks) {
- context.GetPaintController().ForceNewChunk(
- paint_layer_, DisplayItem::kLayerChunkForeground);
- }
+ PaintForegroundForFragmentsWithPhase(PaintPhase::kForeground, layer_fragments,
+ context, local_painting_info,
+ paint_flags);
- PaintForegroundForFragmentsWithPhase(PaintPhase::kForeground,
+ if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
+ paint_layer_.NeedsPaintPhaseDescendantOutlines()) {
+ PaintForegroundForFragmentsWithPhase(PaintPhase::kDescendantOutlinesOnly,
layer_fragments, context,
local_painting_info, paint_flags);
-
- if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
- paint_layer_.NeedsPaintPhaseDescendantOutlines()) {
- PaintForegroundForFragmentsWithPhase(PaintPhase::kDescendantOutlinesOnly,
- layer_fragments, context,
- local_painting_info, paint_flags);
- }
}
}
@@ -878,21 +840,4 @@ void PaintLayerPainter::FillMaskingFragment(GraphicsContext& context,
context.FillRect(snapped_clip_rect, Color::kBlack);
}
-// Generate a no-op DrawingDisplayItem to ensure a non-empty chunk for the
-// filter without content.
-void PaintLayerPainter::PaintEmptyContentForFilters(GraphicsContext& context) {
- DCHECK(paint_layer_.PaintsWithFilters() ||
- paint_layer_.GetLayoutObject().HasBackdropFilter());
-
- ScopedPaintChunkProperties paint_chunk_properties(
- context.GetPaintController(),
- paint_layer_.GetLayoutObject().FirstFragment().LocalBorderBoxProperties(),
- paint_layer_, DisplayItem::kEmptyContentForFilters);
- if (DrawingRecorder::UseCachedDrawingIfPossible(
- context, paint_layer_, DisplayItem::kEmptyContentForFilters))
- return;
- DrawingRecorder recorder(context, paint_layer_,
- DisplayItem::kEmptyContentForFilters);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
index e61f2ceadc5..29e13df3cb4 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.h
@@ -82,8 +82,6 @@ class CORE_EXPORT PaintLayerPainter {
void PaintForegroundForFragments(const PaintLayerFragments&,
GraphicsContext&,
const PaintLayerPaintingInfo&,
- bool selection_only,
- bool force_paint_chunks,
PaintLayerFlags);
void PaintForegroundForFragmentsWithPhase(PaintPhase,
const PaintLayerFragments&,
@@ -107,8 +105,6 @@ class CORE_EXPORT PaintLayerPainter {
const ClipRect&,
const DisplayItemClient&);
- void PaintEmptyContentForFilters(GraphicsContext&);
-
void AdjustForPaintProperties(const GraphicsContext&,
PaintLayerPaintingInfo&,
PaintLayerFlags&);
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
index c2c9d6a4ddc..c191b7a6e9a 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter_test.cc
@@ -48,8 +48,9 @@ class PaintLayerPainterTest : public PaintControllerPaintTest {
INSTANTIATE_PAINT_TEST_SUITE_P(PaintLayerPainterTest);
-TEST_P(PaintLayerPainterTest, CachedSubsequence) {
+TEST_P(PaintLayerPainterTest, CachedSubsequenceAndChunksWithBackgrounds) {
SetBodyInnerHTML(R"HTML(
+ <style>body { margin: 0 }</style>
<div id='container1' style='position: relative; z-index: 1;
width: 200px; height: 200px; background-color: blue'>
<div id='content1' style='position: absolute; width: 100px;
@@ -66,101 +67,179 @@ TEST_P(PaintLayerPainterTest, CachedSubsequence) {
width: 20px; height: 20px; background-color: gray'></div>
)HTML");
- auto& container1 = *GetLayoutObjectByElementId("container1");
- auto& content1 = *GetLayoutObjectByElementId("content1");
- auto& filler1 = *GetLayoutObjectByElementId("filler1");
- auto& container2 = *GetLayoutObjectByElementId("container2");
- auto& content2 = *GetLayoutObjectByElementId("content2");
- auto& filler2 = *GetLayoutObjectByElementId("filler2");
-
+ auto* container1 = GetLayoutObjectByElementId("container1");
+ auto* content1 = GetLayoutObjectByElementId("content1");
+ auto* filler1 = GetLayoutObjectByElementId("filler1");
+ auto* container2 = GetLayoutObjectByElementId("container2");
+ auto* content2 = GetLayoutObjectByElementId("content2");
+ auto* filler2 = GetLayoutObjectByElementId("filler2");
const auto& view_client = ViewScrollingBackgroundClient();
- EXPECT_THAT(
- RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&view_client, kDocumentBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&container1),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&content1),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&filler1),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&container2),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&content2),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&filler2),
- kBackgroundType)));
- auto* container1_layer = ToLayoutBoxModelObject(container1).Layer();
- auto* filler1_layer = ToLayoutBoxModelObject(filler1).Layer();
- auto* container2_layer = ToLayoutBoxModelObject(container2).Layer();
- auto* filler2_layer = ToLayoutBoxModelObject(filler2).Layer();
+ auto* container1_layer = ToLayoutBoxModelObject(container1)->Layer();
+ auto* filler1_layer = ToLayoutBoxModelObject(filler1)->Layer();
+ auto* container2_layer = ToLayoutBoxModelObject(container2)->Layer();
+ auto* filler2_layer = ToLayoutBoxModelObject(filler2)->Layer();
auto chunk_state = GetLayoutView().FirstFragment().ContentsProperties();
- auto view_chunk_type = kDocumentBackgroundType;
- auto chunk_background_type = DisplayItem::kLayerChunkBackground;
- auto chunk_foreground_type =
- DisplayItem::kLayerChunkNormalFlowAndPositiveZOrderChildren;
- auto filler_chunk_type = DisplayItem::PaintPhaseToDrawingType(
- PaintPhase::kSelfBlockBackgroundOnly);
-
- auto check_chunks = [&]() {
- // Check that new paint chunks were forced for |container1| and
- // |container2|.
+ auto check_results = [&]() {
+ EXPECT_THAT(
+ RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&view_client, kDocumentBackgroundType),
+ IsSameId(GetDisplayItemClientFromLayoutObject(container1),
+ kBackgroundType),
+ IsSameId(GetDisplayItemClientFromLayoutObject(content1),
+ kBackgroundType),
+ IsSameId(GetDisplayItemClientFromLayoutObject(filler1),
+ kBackgroundType),
+ IsSameId(GetDisplayItemClientFromLayoutObject(container2),
+ kBackgroundType),
+ IsSameId(GetDisplayItemClientFromLayoutObject(content2),
+ kBackgroundType),
+ IsSameId(GetDisplayItemClientFromLayoutObject(filler2),
+ kBackgroundType)));
+
+ EXPECT_SUBSEQUENCE(*container1_layer, 1, 2);
+ EXPECT_SUBSEQUENCE(*filler1_layer, 2, 3);
+ EXPECT_SUBSEQUENCE(*container2_layer, 3, 4);
+ EXPECT_SUBSEQUENCE(*filler2_layer, 4, 5);
+
+ // Check that new paint chunks were forced for the layers.
EXPECT_THAT(
RootPaintController().PaintChunks(),
ElementsAre(
- IsPaintChunk(0, 1, PaintChunk::Id(view_client, view_chunk_type),
- chunk_state),
+ IsPaintChunk(0, 1),
IsPaintChunk(
- 1, 2, PaintChunk::Id(*container1_layer, chunk_background_type),
- chunk_state),
+ 1, 3,
+ PaintChunk::Id(*container1_layer, DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 0, 200, 200)),
IsPaintChunk(
- 2, 3, PaintChunk::Id(*container1_layer, chunk_foreground_type),
- chunk_state),
- IsPaintChunk(3, 4,
- PaintChunk::Id(*filler1_layer, filler_chunk_type),
- chunk_state),
+ 3, 4, PaintChunk::Id(*filler1_layer, DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 200, 20, 20)),
IsPaintChunk(
- 4, 5, PaintChunk::Id(*container2_layer, chunk_background_type),
- chunk_state),
+ 4, 6,
+ PaintChunk::Id(*container2_layer, DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 220, 200, 200)),
IsPaintChunk(
- 5, 6, PaintChunk::Id(*container2_layer, chunk_foreground_type),
- chunk_state),
- IsPaintChunk(6, 7,
- PaintChunk::Id(*filler2_layer, filler_chunk_type),
- chunk_state)));
+ 6, 7, PaintChunk::Id(*filler2_layer, DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 420, 20, 20))));
};
- check_chunks();
+ check_results();
- To<HTMLElement>(content1.GetNode())
+ To<HTMLElement>(content1->GetNode())
->setAttribute(html_names::kStyleAttr,
"position: absolute; width: 100px; height: 100px; "
"background-color: green");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(PaintWithoutCommit());
EXPECT_EQ(6, NumCachedNewItems());
CommitAndFinishCycle();
+ // We should still have the paint chunks forced by the cached subsequences.
+ check_results();
+}
+
+TEST_P(PaintLayerPainterTest, CachedSubsequenceAndChunksWithoutBackgrounds) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0 }
+ ::-webkit-scrollbar { display: none }
+ </style>
+ <div id='container' style='position: relative; z-index: 0;
+ width: 150px; height: 150px; overflow: scroll'>
+ <div id='content' style='position: relative; z-index: 1;
+ width: 200px; height: 100px'>
+ <div id='inner-content'
+ style='position: absolute; width: 100px; height: 100px'></div>
+ </div>
+ <div id='filler' style='position: relative; z-index: 2;
+ width: 300px; height: 300px'></div>
+ </div>
+ )HTML");
+
+ auto* container = GetLayoutObjectByElementId("container");
+ auto* content = GetLayoutObjectByElementId("content");
+ auto* inner_content = GetLayoutObjectByElementId("inner-content");
+ auto* filler = GetLayoutObjectByElementId("filler");
+ const auto& view_client = ViewScrollingBackgroundClient();
+
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&view_client, kDocumentBackgroundType)));
+
+ auto* container_layer = ToLayoutBoxModelObject(container)->Layer();
+ auto* content_layer = ToLayoutBoxModelObject(content)->Layer();
+ auto* inner_content_layer = ToLayoutBoxModelObject(inner_content)->Layer();
+ auto* filler_layer = ToLayoutBoxModelObject(filler)->Layer();
+
+ EXPECT_SUBSEQUENCE(*container_layer, 1, 5);
+ EXPECT_SUBSEQUENCE(*content_layer, 3, 4);
+ EXPECT_SUBSEQUENCE(*filler_layer, 4, 5);
+
+ auto container_properties =
+ container->FirstFragment().LocalBorderBoxProperties();
+ auto content_properties = container->FirstFragment().ContentsProperties();
+ HitTestData scroll_hit_test;
+ scroll_hit_test.scroll_translation = &content_properties.Transform();
+ scroll_hit_test.scroll_hit_test_rect = IntRect(0, 0, 150, 150);
+
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1),
+ IsPaintChunk(
+ 1, 1, PaintChunk::Id(*container_layer, DisplayItem::kLayerChunk),
+ container_properties, nullptr, IntRect(0, 0, 150, 150)),
+ IsPaintChunk(
+ 1, 1, PaintChunk::Id(*container, DisplayItem::kScrollHitTest),
+ container_properties, &scroll_hit_test, IntRect(0, 0, 150, 150)),
+ IsPaintChunk(1, 1,
+ PaintChunk::Id(*content_layer, DisplayItem::kLayerChunk),
+ content_properties, nullptr, IntRect(0, 0, 200, 100)),
+ IsPaintChunk(
+ 1, 1, PaintChunk::Id(*filler_layer, DisplayItem::kLayerChunk),
+ content_properties, nullptr, IntRect(0, 100, 300, 300))));
+
+ To<HTMLElement>(inner_content->GetNode())
+ ->setAttribute(html_names::kStyleAttr,
+ "position: absolute; width: 100px; height: 100px; "
+ "top: 100px; background-color: green");
+ UpdateAllLifecyclePhasesForTest();
+
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&view_client, kDocumentBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&container1),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&content1),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&filler1),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&container2),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&content2),
- kBackgroundType),
- IsSameId(GetDisplayItemClientFromLayoutObject(&filler2),
+ IsSameId(GetDisplayItemClientFromLayoutObject(inner_content),
kBackgroundType)));
- // We should still have the paint chunks forced by the cached subsequences.
- check_chunks();
+ EXPECT_SUBSEQUENCE(*container_layer, 1, 6);
+ EXPECT_SUBSEQUENCE(*content_layer, 3, 5);
+ EXPECT_SUBSEQUENCE(*filler_layer, 5, 6);
+
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1),
+ IsPaintChunk(
+ 1, 1, PaintChunk::Id(*container_layer, DisplayItem::kLayerChunk),
+ container_properties, nullptr, IntRect(0, 0, 150, 150)),
+ IsPaintChunk(
+ 1, 1, PaintChunk::Id(*container, DisplayItem::kScrollHitTest),
+ container_properties, &scroll_hit_test, IntRect(0, 0, 150, 150)),
+ IsPaintChunk(1, 1,
+ PaintChunk::Id(*content_layer, DisplayItem::kLayerChunk),
+ content_properties, nullptr, IntRect(0, 0, 200, 100)),
+ IsPaintChunk(
+ 1, 2,
+ PaintChunk::Id(*inner_content_layer, DisplayItem::kLayerChunk),
+ content_properties, nullptr, IntRect(0, 100, 100, 100)),
+ IsPaintChunk(
+ 2, 2, PaintChunk::Id(*filler_layer, DisplayItem::kLayerChunk),
+ content_properties, nullptr, IntRect(0, 100, 300, 300))));
}
TEST_P(PaintLayerPainterTest, CachedSubsequenceOnCullRectChange) {
@@ -207,7 +286,8 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnCullRectChange) {
const DisplayItemClient& content3 =
*GetDisplayItemClientFromElementId("content3");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
Paint(IntRect(0, 0, 400, 300));
const auto& background_display_item_client = ViewScrollingBackgroundClient();
@@ -226,7 +306,8 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnCullRectChange) {
IsSameId(&container3, kBackgroundType),
IsSameId(&content3, kBackgroundType)));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(PaintWithoutCommit(IntRect(0, 100, 300, 1000)));
// Container1 becomes partly in the interest rect, but uses cached subsequence
@@ -262,12 +343,14 @@ TEST_P(PaintLayerPainterTest,
InvalidateAll(RootPaintController());
// |target| will be fully painted.
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
Paint(IntRect(0, 0, 400, 300));
// |target| will be partially painted. Should not trigger under-invalidation
// checking DCHECKs.
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
Paint(IntRect(0, 100, 300, 1000));
}
@@ -285,7 +368,8 @@ TEST_P(PaintLayerPainterTest,
height: 100px; background-color: green'></div>
</div>
)HTML");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// PaintResult of all subsequences will be MayBeClippedByCullRect.
Paint(IntRect(0, 0, 50, 300));
@@ -311,7 +395,8 @@ TEST_P(PaintLayerPainterTest,
->setAttribute(html_names::kStyleAttr,
"position: absolute; width: 100px; height: 100px; "
"background-color: green");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(PaintWithoutCommit(IntRect(0, 0, 50, 300)));
EXPECT_EQ(4, NumCachedNewItems());
@@ -340,8 +425,8 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
<div id="change" style="display: none"></div>
)HTML");
- const auto* target_layer =
- ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))->Layer();
+ const auto* target = ToLayoutBox(GetLayoutObjectByElementId("target"));
+ const auto* target_layer = target->Layer();
const auto* content1 = GetLayoutObjectByElementId("content1");
const auto* content2 = GetLayoutObjectByElementId("content2");
const auto& view_client = ViewScrollingBackgroundClient();
@@ -353,13 +438,13 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
target_layer->PreviousCullRect());
// |content2| is out of the cull rect.
- EXPECT_THAT(
- RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
- IsSameId(&view_client, kDocumentBackgroundType),
- IsSameId(content1, kBackgroundType)));
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&view_client, kDocumentBackgroundType),
+ IsSameId(content1, kBackgroundType)));
// |target| created subsequence.
- EXPECT_SUBSEQUENCE(*target_layer, 2, 3);
+ EXPECT_SUBSEQUENCE(*target_layer, 2, 4);
+ EXPECT_EQ(0u, RootPaintController().PaintChunks()[2].size());
+ EXPECT_EQ(1u, RootPaintController().PaintChunks()[3].size());
} else {
EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)),
target_layer->PreviousCullRect());
@@ -369,35 +454,34 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
IsSameId(content1, kBackgroundType)));
// |target| created subsequence.
EXPECT_SUBSEQUENCE(*target_layer, 1, 2);
+ EXPECT_EQ(1u, RootPaintController().PaintChunks()[1].size());
}
// Change something that triggers a repaint but |target| should use cached
// subsequence.
GetDocument().getElementById("change")->setAttribute(html_names::kStyleAttr,
"display: block");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(target_layer->SelfNeedsRepaint());
EXPECT_TRUE(PaintWithoutCommit());
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- EXPECT_EQ(3, NumCachedNewItems());
- else
- EXPECT_EQ(2, NumCachedNewItems());
+ EXPECT_EQ(2, NumCachedNewItems());
CommitAndFinishCycle();
// |target| is still partially painted.
EXPECT_EQ(kMayBeClippedByCullRect, target_layer->PreviousPaintResult());
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // CAP doens't clip the cull rect by the scrolling contents rect, which
+ // CAP doesn't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -4000, 8800, 8600)),
target_layer->PreviousCullRect());
- EXPECT_THAT(
- RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
- IsSameId(&view_client, kDocumentBackgroundType),
- IsSameId(content1, kBackgroundType)));
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&view_client, kDocumentBackgroundType),
+ IsSameId(content1, kBackgroundType)));
// |target| still created subsequence (cached).
- EXPECT_SUBSEQUENCE(*target_layer, 2, 3);
+ EXPECT_SUBSEQUENCE(*target_layer, 2, 4);
+ EXPECT_EQ(0u, RootPaintController().PaintChunks()[2].size());
+ EXPECT_EQ(1u, RootPaintController().PaintChunks()[3].size());
} else {
EXPECT_EQ(CullRect(IntRect(0, 0, 800, 4600)),
target_layer->PreviousCullRect());
@@ -406,39 +490,38 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
IsSameId(content1, kBackgroundType)));
// |target| still created subsequence (cached).
EXPECT_SUBSEQUENCE(*target_layer, 1, 2);
+ EXPECT_EQ(1u, RootPaintController().PaintChunks()[1].size());
}
// Scroll the view so that both |content1| and |content2| are in the interest
// rect.
- GetLayoutView().GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 3000),
- kProgrammaticScroll);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetLayoutView().GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(0, 3000), mojom::blink::ScrollType::kProgrammatic);
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Scrolling doesn't set SelfNeedsRepaint flag. Change of paint dirty rect of
// a partially painted layer will trigger repaint.
EXPECT_FALSE(target_layer->SelfNeedsRepaint());
EXPECT_TRUE(PaintWithoutCommit());
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- EXPECT_EQ(3, NumCachedNewItems());
- else
- EXPECT_EQ(2, NumCachedNewItems());
+ EXPECT_EQ(2, NumCachedNewItems());
CommitAndFinishCycle();
// |target| is still partially painted.
EXPECT_EQ(kMayBeClippedByCullRect, target_layer->PreviousPaintResult());
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // CAP doens't clip the cull rect by the scrolling contents rect, which
+ // CAP doesn't clip the cull rect by the scrolling contents rect, which
// doesn't affect painted results.
EXPECT_EQ(CullRect(IntRect(-4000, -1000, 8800, 8600)),
target_layer->PreviousCullRect());
// Painted result should include both |content1| and |content2|.
- EXPECT_THAT(
- RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
- IsSameId(&view_client, kDocumentBackgroundType),
- IsSameId(content1, kBackgroundType),
- IsSameId(content2, kBackgroundType)));
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&view_client, kDocumentBackgroundType),
+ IsSameId(content1, kBackgroundType),
+ IsSameId(content2, kBackgroundType)));
// |target| still created subsequence (repainted).
EXPECT_SUBSEQUENCE(*target_layer, 2, 4);
+ EXPECT_EQ(0u, RootPaintController().PaintChunks()[2].size());
+ EXPECT_EQ(2u, RootPaintController().PaintChunks()[3].size());
} else {
EXPECT_EQ(CullRect(IntRect(0, 0, 800, 7600)),
target_layer->PreviousCullRect());
@@ -448,10 +531,133 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceRetainsPreviousPaintResult) {
IsSameId(content1, kBackgroundType),
IsSameId(content2, kBackgroundType)));
// |target| still created subsequence (repainted).
- EXPECT_SUBSEQUENCE(*target_layer, 1, 3);
+ EXPECT_SUBSEQUENCE(*target_layer, 1, 2);
+ EXPECT_EQ(2u, RootPaintController().PaintChunks()[1].size());
}
}
+TEST_P(PaintLayerPainterTest, HintedPaintChunksWithBackgrounds) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0 }
+ div { background: blue }
+ </style>
+ <div id='container1' style='position: relative; height: 150px; z-index: 1'>
+ <div id='content1a' style='position: relative; height: 100px'></div>
+ <div id='content1b' style='position: relative; height: 100px'></div>
+ </div>
+ <div id='container2' style='position: relative; z-index: 1'>
+ <div id='content2a' style='position: relative; height: 100px'></div>
+ <div id='content2b' style='position: relative; z-index: -1; height: 100px'></div>
+ </div>
+ )HTML");
+
+ auto* container1 = ToLayoutBox(GetLayoutObjectByElementId("container1"));
+ auto* content1a = ToLayoutBox(GetLayoutObjectByElementId("content1a"));
+ auto* content1b = ToLayoutBox(GetLayoutObjectByElementId("content1b"));
+ auto* container2 = ToLayoutBox(GetLayoutObjectByElementId("container2"));
+ auto* content2a = ToLayoutBox(GetLayoutObjectByElementId("content2a"));
+ auto* content2b = ToLayoutBox(GetLayoutObjectByElementId("content2b"));
+ auto chunk_state = GetLayoutView().FirstFragment().ContentsProperties();
+
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ IsSameId(container1, kBackgroundType),
+ IsSameId(content1a, kBackgroundType),
+ IsSameId(content1b, kBackgroundType),
+ IsSameId(container2, kBackgroundType),
+ IsSameId(content2b, kBackgroundType),
+ IsSameId(content2a, kBackgroundType)));
+
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ chunk_state),
+ // Includes |container1| and |content1a|.
+ IsPaintChunk(
+ 1, 3,
+ PaintChunk::Id(*container1->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 0, 800, 150)),
+ // Includes |content1b| which overflows |container1|.
+ IsPaintChunk(
+ 3, 4,
+ PaintChunk::Id(*content1b->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 100, 800, 100)),
+ IsPaintChunk(
+ 4, 5,
+ PaintChunk::Id(*container2->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 150, 800, 200)),
+ IsPaintChunk(
+ 5, 6,
+ PaintChunk::Id(*content2b->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 250, 800, 100)),
+ IsPaintChunk(
+ 6, 7,
+ PaintChunk::Id(*content2a->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 150, 800, 100))));
+}
+
+TEST_P(PaintLayerPainterTest, HintedPaintChunksWithoutBackgrounds) {
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin: 0 }</style>
+ <div id='container1' style='position: relative; height: 150px; z-index: 1'>
+ <div id='content1a' style='position: relative; height: 100px'></div>
+ <div id='content1b' style='position: relative; height: 100px'></div>
+ </div>
+ <div id='container2' style='position: relative; z-index: 1'>
+ <div id='content2a' style='position: relative; height: 100px'></div>
+ <div id='content2b'
+ style='position: relative; z-index: -1; height: 100px'></div>
+ </div>
+ )HTML");
+
+ auto* container1 = ToLayoutBox(GetLayoutObjectByElementId("container1"));
+ auto* content1b = ToLayoutBox(GetLayoutObjectByElementId("content1b"));
+ auto* container2 = ToLayoutBox(GetLayoutObjectByElementId("container2"));
+ auto* content2a = ToLayoutBox(GetLayoutObjectByElementId("content2a"));
+ auto* content2b = ToLayoutBox(GetLayoutObjectByElementId("content2b"));
+ auto chunk_state = GetLayoutView().FirstFragment().ContentsProperties();
+
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType)));
+
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(
+ IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ chunk_state),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*container1->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 0, 800, 150)),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*content1b->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 100, 800, 100)),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*container2->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 150, 800, 200)),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*content2b->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 250, 800, 100)),
+ IsPaintChunk(
+ 1, 1,
+ PaintChunk::Id(*content2a->Layer(), DisplayItem::kLayerChunk),
+ chunk_state, nullptr, IntRect(0, 150, 800, 100))));
+}
+
TEST_P(PaintLayerPainterTest, PaintPhaseOutline) {
AtomicString style_without_outline =
"width: 50px; height: 50px; background-color: green";
@@ -503,7 +709,8 @@ TEST_P(PaintLayerPainterTest, PaintPhaseOutline) {
// same layer has outline.
To<HTMLElement>(outline_div.GetNode())
->setAttribute(html_names::kStyleAttr, style_with_outline);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseDescendantOutlines());
EXPECT_FALSE(non_self_painting_layer.NeedsPaintPhaseDescendantOutlines());
Paint();
@@ -558,7 +765,8 @@ TEST_P(PaintLayerPainterTest, PaintPhaseFloat) {
// has float.
To<HTMLElement>(float_div.GetNode())
->setAttribute(html_names::kStyleAttr, style_with_float);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseFloat());
EXPECT_FALSE(non_self_painting_layer.NeedsPaintPhaseFloat());
Paint();
@@ -622,75 +830,6 @@ TEST_P(PaintLayerPainterTest, PaintPhaseFloatUnderInlineLayer) {
DisplayItem::kBoxDecorationBackground));
}
-TEST_P(PaintLayerPainterTest, PaintPhaseBlockBackground) {
- AtomicString style_without_background = "width: 50px; height: 50px";
- AtomicString style_with_background =
- "background: blue; " + style_without_background;
- SetBodyInnerHTML(R"HTML(
- <div id='self-painting-layer' style='position: absolute'>
- <div id='non-self-painting-layer' style='overflow: hidden'>
- <div>
- <div id='background'></div>
- </div>
- </div>
- </div>
- )HTML");
- LayoutObject& background_div =
- *GetDocument().getElementById("background")->GetLayoutObject();
- To<HTMLElement>(background_div.GetNode())
- ->setAttribute(html_names::kStyleAttr, style_without_background);
- UpdateAllLifecyclePhasesForTest();
-
- LayoutBoxModelObject& self_painting_layer_object = *ToLayoutBoxModelObject(
- GetDocument().getElementById("self-painting-layer")->GetLayoutObject());
- PaintLayer& self_painting_layer = *self_painting_layer_object.Layer();
- ASSERT_TRUE(self_painting_layer.IsSelfPaintingLayer());
- PaintLayer& non_self_painting_layer =
- *ToLayoutBoxModelObject(GetDocument()
- .getElementById("non-self-painting-layer")
- ->GetLayoutObject())
- ->Layer();
- ASSERT_FALSE(non_self_painting_layer.IsSelfPaintingLayer());
- ASSERT_TRUE(&non_self_painting_layer == background_div.EnclosingLayer());
-
- EXPECT_FALSE(self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
- EXPECT_FALSE(
- non_self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
-
- // Background on the self-painting-layer node itself doesn't affect
- // PaintPhaseDescendantBlockBackgrounds.
- To<HTMLElement>(self_painting_layer_object.GetNode())
- ->setAttribute(html_names::kStyleAttr,
- "position: absolute; background: green");
- UpdateAllLifecyclePhasesForTest();
- EXPECT_FALSE(self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
- EXPECT_FALSE(
- non_self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
- EXPECT_TRUE(DisplayItemListContains(
- RootPaintController().GetDisplayItemList(), self_painting_layer_object,
- DisplayItem::kBoxDecorationBackground));
-
- // needsPaintPhaseDescendantBlockBackgrounds should be set when any descendant
- // on the same layer has Background.
- To<HTMLElement>(background_div.GetNode())
- ->setAttribute(html_names::kStyleAttr, style_with_background);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
- EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
- EXPECT_FALSE(
- non_self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
- Paint();
- EXPECT_TRUE(DisplayItemListContains(
- RootPaintController().GetDisplayItemList(), background_div,
- DisplayItem::kBoxDecorationBackground));
-
- // needsPaintPhaseDescendantBlockBackgrounds should be reset when no outline
- // is actually painted.
- To<HTMLElement>(background_div.GetNode())
- ->setAttribute(html_names::kStyleAttr, style_without_background);
- UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(self_painting_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
-}
-
TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnLayerAddition) {
SetBodyInnerHTML(R"HTML(
<div id='will-be-layer'>
@@ -712,7 +851,6 @@ TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnLayerAddition) {
->Layer();
EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantOutlines());
EXPECT_TRUE(html_layer.NeedsPaintPhaseFloat());
- EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
To<HTMLElement>(layer_div.GetNode())
->setAttribute(html_names::kStyleAttr, "position: relative");
@@ -722,7 +860,6 @@ TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnLayerAddition) {
ASSERT_TRUE(layer.IsSelfPaintingLayer());
EXPECT_TRUE(layer.NeedsPaintPhaseDescendantOutlines());
EXPECT_TRUE(layer.NeedsPaintPhaseFloat());
- EXPECT_TRUE(layer.NeedsPaintPhaseDescendantBlockBackgrounds());
}
TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingSelfPainting) {
@@ -747,7 +884,6 @@ TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingSelfPainting) {
GetDocument().documentElement()->GetLayoutObject())
->Layer();
EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantOutlines());
- EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
To<HTMLElement>(layer_div.GetNode())
->setAttribute(
@@ -757,7 +893,6 @@ TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingSelfPainting) {
PaintLayer& layer = *layer_div.Layer();
ASSERT_TRUE(layer.IsSelfPaintingLayer());
EXPECT_TRUE(layer.NeedsPaintPhaseDescendantOutlines());
- EXPECT_TRUE(layer.NeedsPaintPhaseDescendantBlockBackgrounds());
}
TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingNonSelfPainting) {
@@ -780,14 +915,12 @@ TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingNonSelfPainting) {
PaintLayer& layer = *layer_div.Layer();
EXPECT_TRUE(layer.IsSelfPaintingLayer());
EXPECT_TRUE(layer.NeedsPaintPhaseDescendantOutlines());
- EXPECT_TRUE(layer.NeedsPaintPhaseDescendantBlockBackgrounds());
PaintLayer& html_layer =
*ToLayoutBoxModelObject(
GetDocument().documentElement()->GetLayoutObject())
->Layer();
EXPECT_FALSE(html_layer.NeedsPaintPhaseDescendantOutlines());
- EXPECT_FALSE(html_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
To<HTMLElement>(layer_div.GetNode())
->setAttribute(html_names::kStyleAttr,
@@ -795,52 +928,6 @@ TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingNonSelfPainting) {
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(layer.IsSelfPaintingLayer());
EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantOutlines());
- EXPECT_TRUE(html_layer.NeedsPaintPhaseDescendantBlockBackgrounds());
-}
-
-TEST_P(PaintLayerPainterTest,
- TableCollapsedBorderNeedsPaintPhaseDescendantBlockBackgrounds) {
- // "position: relative" makes the table and td self-painting layers.
- // The table's layer should be marked needsPaintPhaseDescendantBlockBackground
- // because it will paint collapsed borders in the phase.
- SetBodyInnerHTML(R"HTML(
- <table id='table' style='position: relative; border-collapse: collapse'>
- <tr><td style='position: relative; border: 1px solid green'>
- Cell
- </td></tr>
- </table>
- )HTML");
-
- LayoutBoxModelObject& table =
- *ToLayoutBoxModelObject(GetLayoutObjectByElementId("table"));
- ASSERT_TRUE(table.HasLayer());
- PaintLayer& layer = *table.Layer();
- EXPECT_TRUE(layer.IsSelfPaintingLayer());
- EXPECT_TRUE(layer.NeedsPaintPhaseDescendantBlockBackgrounds());
-}
-
-TEST_P(PaintLayerPainterTest,
- TableCollapsedBorderNeedsPaintPhaseDescendantBlockBackgroundsDynamic) {
- SetBodyInnerHTML(R"HTML(
- <table id='table' style='position: relative'>
- <tr><td style='position: relative; border: 1px solid green'>
- Cell
- </td></tr>
- </table>
- )HTML");
-
- LayoutBoxModelObject& table =
- *ToLayoutBoxModelObject(GetLayoutObjectByElementId("table"));
- ASSERT_TRUE(table.HasLayer());
- PaintLayer& layer = *table.Layer();
- EXPECT_TRUE(layer.IsSelfPaintingLayer());
- EXPECT_FALSE(layer.NeedsPaintPhaseDescendantBlockBackgrounds());
-
- To<HTMLElement>(table.GetNode())
- ->setAttribute(html_names::kStyleAttr,
- "position: relative; border-collapse: collapse");
- UpdateAllLifecyclePhasesForTest();
- EXPECT_TRUE(layer.NeedsPaintPhaseDescendantBlockBackgrounds());
}
TEST_P(PaintLayerPainterTest, DontPaintWithTinyOpacity) {
@@ -1035,21 +1122,21 @@ TEST_P(PaintLayerPainterTestCAP, TallScrolledLayerCullRect) {
EXPECT_EQ(IntRect(-4000, -4000, 8800, 8600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 6000),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 6000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(-4000, 2000, 8800, 8600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 6500),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 6500), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Used the previous cull rect because the scroll amount is small.
EXPECT_EQ(IntRect(-4000, 2000, 8800, 8600),
GetPaintLayerByElementId("target")->PreviousCullRect().Rect());
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 6600),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 6600), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Used new cull rect.
EXPECT_EQ(IntRect(-4000, 2600, 8800, 8600),
@@ -1093,14 +1180,11 @@ TEST_P(PaintLayerPainterTestCAP, WholeDocumentCullRect) {
EXPECT_THAT(
RootPaintController().GetDisplayItemList(),
UnorderedElementsAre(
- IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
IsSameId(&ViewScrollingBackgroundClient(), kDocumentBackgroundType),
IsSameId(GetDisplayItemClientFromElementId("relative"),
kBackgroundType),
IsSameId(GetDisplayItemClientFromElementId("normal"),
kBackgroundType),
- IsSameId(GetLayoutObjectByElementId("scroll"),
- DisplayItem::kScrollHitTest),
IsSameId(GetDisplayItemClientFromElementId("scroll"),
kBackgroundType),
IsSameId(&ToLayoutBox(GetLayoutObjectByElementId("scroll"))
@@ -1124,7 +1208,7 @@ TEST_P(PaintLayerPainterTestCAP, VerticalRightLeftWritingModeDocument) {
)HTML");
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(-5000, 0), kProgrammaticScroll);
+ ScrollOffset(-5000, 0), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// A scroll by -5000px is equivalent to a scroll by (10000 - 5000 - 800)px =
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index c2ff5b6ecf3..01c3537f381 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -49,9 +49,11 @@
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/snap_selection_strategy.h"
#include "cc/layers/picture_layer.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
+#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
@@ -98,6 +100,8 @@
#include "third_party/blink/renderer/core/scroll/smooth_scroll_sequencer.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "ui/base/ui_base_features.h"
namespace blink {
@@ -123,6 +127,7 @@ PaintLayerScrollableArea::PaintLayerScrollableArea(PaintLayer& layer)
needs_composited_scrolling_(false),
rebuild_horizontal_scrollbar_layer_(false),
rebuild_vertical_scrollbar_layer_(false),
+ previous_vertical_scrollbar_on_left_(false),
needs_scroll_offset_clamp_(false),
needs_relayout_(false),
had_horizontal_scrollbar_before_relayout_(false),
@@ -224,11 +229,32 @@ void PaintLayerScrollableArea::DisposeImpl() {
sequencer->DidDisposeScrollableArea(*this);
RunScrollCompleteCallbacks();
+ InvalidateScrollTimeline();
layer_ = nullptr;
}
-void PaintLayerScrollableArea::Trace(blink::Visitor* visitor) {
+void PaintLayerScrollableArea::ApplyPendingHistoryRestoreScrollOffset() {
+ if (!pending_view_state_)
+ return;
+
+ // TODO(pnoland): attempt to restore the anchor in more places than this.
+ // Anchor-based restore should allow for earlier restoration.
+ bool did_restore = RestoreScrollAnchor(
+ {pending_view_state_->scroll_anchor_data_.selector_,
+ LayoutPoint(pending_view_state_->scroll_anchor_data_.offset_.x(),
+ pending_view_state_->scroll_anchor_data_.offset_.y()),
+ pending_view_state_->scroll_anchor_data_.simhash_});
+ if (!did_restore) {
+ SetScrollOffset(pending_view_state_->scroll_offset_,
+ mojom::blink::ScrollType::kProgrammatic,
+ mojom::blink::ScrollBehavior::kAuto);
+ }
+
+ pending_view_state_.reset();
+}
+
+void PaintLayerScrollableArea::Trace(Visitor* visitor) {
visitor->Trace(scrollbar_manager_);
visitor->Trace(scroll_anchor_);
visitor->Trace(scrolling_background_display_item_client_);
@@ -335,8 +361,7 @@ static int CornerStart(const LayoutBox& box,
return max_x - thickness - box.StyleRef().BorderRightWidth();
}
-IntRect PaintLayerScrollableArea::PaintLayerScrollableArea::CornerRect(
- const IntRect& bounds) const {
+IntRect PaintLayerScrollableArea::CornerRect() const {
int horizontal_thickness;
int vertical_thickness;
if (!VerticalScrollbar() && !HorizontalScrollbar()) {
@@ -362,9 +387,10 @@ IntRect PaintLayerScrollableArea::PaintLayerScrollableArea::CornerRect(
horizontal_thickness = VerticalScrollbar()->ScrollbarThickness();
vertical_thickness = HorizontalScrollbar()->ScrollbarThickness();
}
- return IntRect(CornerStart(*GetLayoutBox(), bounds.X(), bounds.MaxX(),
+ IntSize border_box_size = PixelSnappedBorderBoxSize();
+ return IntRect(CornerStart(*GetLayoutBox(), 0, border_box_size.Width(),
horizontal_thickness),
- bounds.MaxY() - vertical_thickness -
+ border_box_size.Height() - vertical_thickness -
GetLayoutBox()->StyleRef().BorderBottomWidth(),
horizontal_thickness, vertical_thickness);
}
@@ -380,8 +406,7 @@ IntRect PaintLayerScrollableArea::ScrollCornerRect() const {
bool has_resizer = GetLayoutBox()->StyleRef().HasResize();
if ((has_horizontal_bar && has_vertical_bar) ||
(has_resizer && (has_horizontal_bar || has_vertical_bar))) {
- return CornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
- Layer()->SubpixelAccumulation()));
+ return CornerRect();
}
return IntRect();
}
@@ -466,7 +491,7 @@ int PaintLayerScrollableArea::ScrollSize(
void PaintLayerScrollableArea::UpdateScrollOffset(
const ScrollOffset& new_offset,
- ScrollType scroll_type) {
+ mojom::blink::ScrollType scroll_type) {
if (HasBeenDisposed() || GetScrollOffset() == new_offset)
return;
@@ -494,7 +519,7 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
// should be impacted by a scroll).
if (!frame_view->IsInPerformLayout()) {
if (!Layer()->IsRootLayer()) {
- Layer()->SetNeedsCompositingInputsUpdate();
+ Layer()->SetNeedsCompositingInputsUpdate(false);
Layer()->ClearClipRects();
}
@@ -509,12 +534,21 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
else
frame_view->SetNeedsUpdateGeometries();
}
- UpdateCompositingLayersAfterScroll();
- GetLayoutBox()->MayUpdateHoverWhenContentUnderMouseChanged(
- frame->GetEventHandler());
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ if (auto* scrolling_coordinator = GetScrollingCoordinator())
+ scrolling_coordinator->UpdateCompositorScrollOffset(*frame, *this);
+ } else {
+ UpdateCompositingLayersAfterScroll();
+ }
- if (scroll_type == kUserScroll || scroll_type == kCompositorScroll) {
+ // The ScrollOffsetTranslation paint property depends on the scroll offset.
+ // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
+ GetLayoutBox()->SetNeedsPaintPropertyUpdatePreservingCachedRects();
+ InvalidateScrollTimeline();
+
+ if (scroll_type == mojom::blink::ScrollType::kUser ||
+ scroll_type == mojom::blink::ScrollType::kCompositor) {
Page* page = frame->GetPage();
if (page)
page->GetChromeClient().ClearToolTip(*frame);
@@ -522,10 +556,6 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
InvalidatePaintForScrollOffsetChange();
- // The scrollOffsetTranslation paint property depends on the scroll offset.
- // (see: PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation).
- GetLayoutBox()->SetNeedsPaintPropertyUpdate();
-
// Don't enqueue a scroll event yet for scroll reasons that are not about
// explicit changes to scroll. Instead, only do so at the time of the next
// lifecycle update, to avoid scroll events that are out of date or don't
@@ -535,7 +565,8 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
// events is at the next lifecycle update (*).
//
// (*) https://html.spec.whatwg.org/#update-the-rendering steps
- if (scroll_type == kClampingScroll || scroll_type == kAnchoringScroll) {
+ if (scroll_type == mojom::blink::ScrollType::kClamping ||
+ scroll_type == mojom::blink::ScrollType::kAnchoring) {
if (GetLayoutBox()->GetNode())
frame_view->SetNeedsEnqueueScrollEvent(this);
} else {
@@ -549,7 +580,8 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
if (is_root_layer) {
frame_view->GetFrame().Loader().SaveScrollState();
frame_view->DidChangeScrollOffset();
- if (scroll_type == kCompositorScroll || scroll_type == kUserScroll) {
+ if (scroll_type == mojom::blink::ScrollType::kCompositor ||
+ scroll_type == mojom::blink::ScrollType::kUser) {
if (DocumentLoader* document_loader = frame->Loader().GetDocumentLoader())
document_loader->GetInitialScrollState().was_scrolled_by_user = true;
}
@@ -559,8 +591,8 @@ void PaintLayerScrollableArea::UpdateScrollOffset(
anchor->DidScroll(scroll_type);
if (IsExplicitScrollType(scroll_type)) {
- if (scroll_type != kCompositorScroll)
- ShowOverlayScrollbars();
+ if (scroll_type != mojom::blink::ScrollType::kCompositor)
+ ShowNonMacOverlayScrollbars();
GetScrollAnchor()->Clear();
}
if (ContentCaptureManager* manager =
@@ -579,7 +611,7 @@ void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
auto* frame_view = box->GetFrameView();
frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(*box);
- if (box->IsLayoutView() && frame_view->HasViewportConstrainedObjects() &&
+ if (IsA<LayoutView>(box) && frame_view->HasViewportConstrainedObjects() &&
!frame_view->InvalidateViewportConstrainedObjects()) {
box->SetShouldDoFullPaintInvalidation();
box->SetSubtreeShouldCheckForPaintInvalidation();
@@ -590,28 +622,24 @@ void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange() {
if (Layer()->EnclosingPaginationLayer())
box->SetSubtreeShouldCheckForPaintInvalidation();
- // If not composited, background always paints into the main graphics layer.
- bool background_paint_in_graphics_layer = true;
- bool background_paint_in_scrolling_contents = false;
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
- UsesCompositedScrolling()) {
+ if (!box->BackgroundNeedsFullPaintInvalidation()) {
auto background_paint_location = box->GetBackgroundPaintLocation();
- background_paint_in_graphics_layer =
+ bool background_paint_in_graphics_layer =
background_paint_location & kBackgroundPaintInGraphicsLayer;
- background_paint_in_scrolling_contents =
+ bool background_paint_in_scrolling_contents =
background_paint_location & kBackgroundPaintInScrollingContents;
- }
- // Both local attachment background painted in graphics layer and normal
- // attachment background painted in scrolling contents require paint
- // invalidation. Fixed attachment background has been dealt with in
- // frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll().
- auto background_layers = box->StyleRef().BackgroundLayers();
- if ((background_layers.AnyLayerHasLocalAttachmentImage() &&
- background_paint_in_graphics_layer) ||
- (background_layers.AnyLayerHasDefaultAttachmentImage() &&
- background_paint_in_scrolling_contents))
- box->SetBackgroundNeedsFullPaintInvalidation();
+ // Both local attachment background painted in graphics layer and normal
+ // attachment background painted in scrolling contents require paint
+ // invalidation. Fixed attachment background has been dealt with in
+ // frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll().
+ auto background_layers = box->StyleRef().BackgroundLayers();
+ if ((background_layers.AnyLayerHasLocalAttachmentImage() &&
+ background_paint_in_graphics_layer) ||
+ (background_layers.AnyLayerHasDefaultAttachmentImage() &&
+ background_paint_in_scrolling_contents))
+ box->SetBackgroundNeedsFullPaintInvalidation();
+ }
// If any scrolling content might have been clipped by a cull rect, then
// that cull rect could be affected by scroll offset. For composited
@@ -684,7 +712,8 @@ IntSize PaintLayerScrollableArea::MaximumScrollOffsetInt() const {
}
void PaintLayerScrollableArea::VisibleSizeChanged() {
- ShowOverlayScrollbars();
+ InvalidateScrollTimeline();
+ ShowNonMacOverlayScrollbars();
}
PhysicalRect PaintLayerScrollableArea::LayoutContentRect(
@@ -759,6 +788,7 @@ void PaintLayerScrollableArea::ContentsResized() {
// Need to update the bounds of the scroll property.
GetLayoutBox()->SetNeedsPaintPropertyUpdate();
Layer()->SetNeedsCompositingInputsUpdate();
+ InvalidateScrollTimeline();
}
IntPoint PaintLayerScrollableArea::LastKnownMousePosition() const {
@@ -849,18 +879,19 @@ bool PaintLayerScrollableArea::UserInputScrollable(
if (GetLayoutBox()->IsIntrinsicallyScrollable(orientation))
return true;
- if (GetLayoutBox()->IsLayoutView()) {
+ if (IsA<LayoutView>(GetLayoutBox())) {
Document& document = GetLayoutBox()->GetDocument();
Element* fullscreen_element = Fullscreen::FullscreenElementFrom(document);
if (fullscreen_element && fullscreen_element != document.documentElement())
return false;
- ScrollbarMode h_mode;
- ScrollbarMode v_mode;
- ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
- ScrollbarMode mode =
+ mojom::blink::ScrollbarMode h_mode;
+ mojom::blink::ScrollbarMode v_mode;
+ To<LayoutView>(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
+ mojom::blink::ScrollbarMode mode =
(orientation == kHorizontalScrollbar) ? h_mode : v_mode;
- return mode == ScrollbarMode::kAuto || mode == ScrollbarMode::kAlwaysOn;
+ return mode == mojom::blink::ScrollbarMode::kAuto ||
+ mode == mojom::blink::ScrollbarMode::kAlwaysOn;
}
EOverflow overflow_style = (orientation == kHorizontalScrollbar)
@@ -929,9 +960,10 @@ void PaintLayerScrollableArea::UpdateScrollDimensions() {
new_overflow_rect.Unite(PhysicalRect(
new_overflow_rect.offset, LayoutContentRect(kExcludeScrollbars).size));
- if (overflow_rect_.size != new_overflow_rect.size)
- ContentsResized();
+ bool resized = overflow_rect_.size != new_overflow_rect.size;
overflow_rect_ = new_overflow_rect;
+ if (resized)
+ ContentsResized();
UpdateScrollOrigin();
}
@@ -956,7 +988,7 @@ void PaintLayerScrollableArea::UpdateScrollbarProportions() {
void PaintLayerScrollableArea::SetScrollOffsetUnconditionally(
const ScrollOffset& offset,
- ScrollType scroll_type) {
+ mojom::blink::ScrollType scroll_type) {
CancelScrollAnimation();
ScrollOffsetChanged(offset, scroll_type);
}
@@ -1039,7 +1071,7 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
GetLayoutBox()->IsHorizontalWritingMode()) ||
(horizontal_scrollbar_should_change &&
!GetLayoutBox()->IsHorizontalWritingMode())) {
- GetLayoutBox()->SetPreferredLogicalWidthsDirty();
+ GetLayoutBox()->SetIntrinsicLogicalWidthsDirty();
}
if (IsManagedByLayoutNG(*GetLayoutBox())) {
// If the box is managed by LayoutNG, don't go here. We don't want to
@@ -1080,7 +1112,9 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
} else if (!HasScrollbar() && resizer_will_change) {
Layer()->DirtyStackingContextZOrderLists();
}
-
+ // The snap container data will be updated at the end of the layout update. If
+ // the data changes, then this will try to re-snap.
+ SetSnapContainerDataNeedsUpdate(true);
{
// Hits in
// compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html.
@@ -1091,13 +1125,6 @@ void PaintLayerScrollableArea::UpdateAfterLayout() {
UpdateScrollbarProportions();
}
- if (!scrollbars_are_frozen && HasOverlayScrollbars()) {
- if (!ScrollSize(kHorizontalScrollbar))
- SetHasHorizontalScrollbar(false);
- if (!ScrollSize(kVerticalScrollbar))
- SetHasVerticalScrollbar(false);
- }
-
ClampScrollOffsetAfterOverflowChange();
if (!scrollbars_are_frozen) {
@@ -1123,10 +1150,12 @@ void PaintLayerScrollableArea::ClampScrollOffsetAfterOverflowChange() {
}
UpdateScrollDimensions();
- if (ScrollOriginChanged())
+ if (ScrollOriginChanged()) {
SetScrollOffsetUnconditionally(ClampScrollOffset(GetScrollOffset()));
- else
- ScrollableArea::SetScrollOffset(GetScrollOffset(), kClampingScroll);
+ } else {
+ ScrollableArea::SetScrollOffset(GetScrollOffset(),
+ mojom::blink::ScrollType::kClamping);
+ }
SetNeedsScrollOffsetClamp(false);
ResetScrollOriginChanged();
@@ -1158,8 +1187,7 @@ void PaintLayerScrollableArea::DidChangeGlobalRootScroller() {
// Recalculate the snap container data since the scrolling behaviour for this
// layout box changed (i.e. it either became the layout viewport or it
// is no longer the layout viewport).
- GetLayoutBox()->GetDocument().GetSnapCoordinator().UpdateSnapContainerData(
- *GetLayoutBox());
+ SetSnapContainerDataNeedsUpdate(true);
}
bool PaintLayerScrollableArea::ShouldPerformScrollAnchoring() const {
@@ -1191,7 +1219,8 @@ PaintLayerScrollableArea::GetTimerTaskRunner() const {
return GetLayoutBox()->GetFrame()->GetTaskRunner(TaskType::kInternalDefault);
}
-ScrollBehavior PaintLayerScrollableArea::ScrollBehaviorStyle() const {
+mojom::blink::ScrollBehavior PaintLayerScrollableArea::ScrollBehaviorStyle()
+ const {
return GetLayoutBox()->StyleRef().GetScrollBehavior();
}
@@ -1264,9 +1293,8 @@ void PaintLayerScrollableArea::UpdateAfterStyleChange(
bool needs_horizontal_scrollbar;
bool needs_vertical_scrollbar;
- // We add auto scrollbars only during layout to prevent spurious activations.
ComputeScrollbarExistence(needs_horizontal_scrollbar,
- needs_vertical_scrollbar, kForbidAddingAutoBars);
+ needs_vertical_scrollbar, kOverflowIndependent);
UpdateResizerStyle(old_style);
@@ -1288,20 +1316,6 @@ void PaintLayerScrollableArea::UpdateAfterStyleChange(
LayoutBlock::ScrollbarChangeContext::kStyleChange);
}
- // With overflow: scroll, scrollbars are always visible but may be disabled.
- // When switching to another value, we need to re-enable them (see bug 11985).
- if (HasHorizontalScrollbar() && old_style &&
- old_style->OverflowX() == EOverflow::kScroll &&
- GetLayoutBox()->StyleRef().OverflowX() != EOverflow::kScroll) {
- HorizontalScrollbar()->SetEnabled(true);
- }
-
- if (HasVerticalScrollbar() && old_style &&
- old_style->OverflowY() == EOverflow::kScroll &&
- GetLayoutBox()->StyleRef().OverflowY() != EOverflow::kScroll) {
- VerticalScrollbar()->SetEnabled(true);
- }
-
// FIXME: Need to detect a swap from custom to native scrollbars (and vice
// versa).
if (HorizontalScrollbar())
@@ -1310,6 +1324,14 @@ void PaintLayerScrollableArea::UpdateAfterStyleChange(
VerticalScrollbar()->StyleChanged();
UpdateScrollCornerStyle();
+
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ bool vertical_scrollbar_on_left = ShouldPlaceVerticalScrollbarOnLeft();
+ if (vertical_scrollbar_on_left != previous_vertical_scrollbar_on_left_) {
+ rebuild_vertical_scrollbar_layer_ = true;
+ previous_vertical_scrollbar_on_left_ = vertical_scrollbar_on_left;
+ }
+ }
}
void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
@@ -1339,58 +1361,51 @@ void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() {
UpdateScrollableAreaSet();
}
-IntRect PaintLayerScrollableArea::RectForHorizontalScrollbar(
- const IntRect& border_box_rect) const {
+IntRect PaintLayerScrollableArea::RectForHorizontalScrollbar() const {
if (!HasHorizontalScrollbar())
return IntRect();
const IntRect& scroll_corner = ScrollCornerRect();
-
+ IntSize border_box_size = PixelSnappedBorderBoxSize();
return IntRect(
- HorizontalScrollbarStart(border_box_rect.X()),
- border_box_rect.MaxY() - GetLayoutBox()->BorderBottom().ToInt() -
+ HorizontalScrollbarStart(),
+ border_box_size.Height() - GetLayoutBox()->BorderBottom().ToInt() -
HorizontalScrollbar()->ScrollbarThickness(),
- border_box_rect.Width() -
+ border_box_size.Width() -
(GetLayoutBox()->BorderLeft() + GetLayoutBox()->BorderRight())
.ToInt() -
scroll_corner.Width(),
HorizontalScrollbar()->ScrollbarThickness());
}
-IntRect PaintLayerScrollableArea::RectForVerticalScrollbar(
- const IntRect& border_box_rect) const {
+IntRect PaintLayerScrollableArea::RectForVerticalScrollbar() const {
if (!HasVerticalScrollbar())
return IntRect();
const IntRect& scroll_corner = ScrollCornerRect();
-
return IntRect(
- VerticalScrollbarStart(border_box_rect.X(), border_box_rect.MaxX()),
- border_box_rect.Y() + GetLayoutBox()->BorderTop().ToInt(),
+ VerticalScrollbarStart(), GetLayoutBox()->BorderTop().ToInt(),
VerticalScrollbar()->ScrollbarThickness(),
- border_box_rect.Height() -
+ PixelSnappedBorderBoxSize().Height() -
(GetLayoutBox()->BorderTop() + GetLayoutBox()->BorderBottom())
.ToInt() -
scroll_corner.Height());
}
-int PaintLayerScrollableArea::VerticalScrollbarStart(int min_x,
- int max_x) const {
+int PaintLayerScrollableArea::VerticalScrollbarStart() const {
if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
- return min_x + GetLayoutBox()->BorderLeft().ToInt();
- return max_x - GetLayoutBox()->BorderRight().ToInt() -
+ return GetLayoutBox()->BorderLeft().ToInt();
+ return PixelSnappedBorderBoxSize().Width() -
+ GetLayoutBox()->BorderRight().ToInt() -
VerticalScrollbar()->ScrollbarThickness();
}
-int PaintLayerScrollableArea::HorizontalScrollbarStart(int min_x) const {
- int x = min_x + GetLayoutBox()->BorderLeft().ToInt();
- if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
- x += HasVerticalScrollbar()
- ? VerticalScrollbar()->ScrollbarThickness()
- : ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
- Layer()->SubpixelAccumulation()),
- kResizerForPointer)
- .Width();
+int PaintLayerScrollableArea::HorizontalScrollbarStart() const {
+ int x = GetLayoutBox()->BorderLeft().ToInt();
+ if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
+ x += HasVerticalScrollbar() ? VerticalScrollbar()->ScrollbarThickness()
+ : ResizerCornerRect(kResizerForPointer).Width();
+ }
return x;
}
@@ -1399,13 +1414,12 @@ IntSize PaintLayerScrollableArea::ScrollbarOffset(
// TODO(szager): Factor out vertical offset calculation into other methods,
// for symmetry with *ScrollbarStart methods for horizontal offset.
if (&scrollbar == VerticalScrollbar()) {
- return IntSize(
- VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
- GetLayoutBox()->BorderTop().ToInt());
+ return IntSize(VerticalScrollbarStart(),
+ GetLayoutBox()->BorderTop().ToInt());
}
if (&scrollbar == HorizontalScrollbar()) {
- return IntSize(HorizontalScrollbarStart(0),
+ return IntSize(HorizontalScrollbarStart(),
GetLayoutBox()->BorderTop().ToInt() +
VisibleContentRect(kIncludeScrollbars).Height() -
HorizontalScrollbar()->ScrollbarThickness());
@@ -1417,7 +1431,7 @@ IntSize PaintLayerScrollableArea::ScrollbarOffset(
static inline const LayoutObject& ScrollbarStyleSource(
const LayoutBox& layout_box) {
- if (layout_box.IsLayoutView()) {
+ if (IsA<LayoutView>(layout_box)) {
Document& doc = layout_box.GetDocument();
if (Settings* settings = doc.GetSettings()) {
if (!settings->GetAllowCustomScrollbarInMainFrame() &&
@@ -1532,45 +1546,89 @@ void PaintLayerScrollableArea::ComputeScrollbarExistence(
return;
}
- needs_horizontal_scrollbar = GetLayoutBox()->ScrollsOverflowX();
- needs_vertical_scrollbar = GetLayoutBox()->ScrollsOverflowY();
+ mojom::blink::ScrollbarMode h_mode = mojom::blink::ScrollbarMode::kAuto;
+ mojom::blink::ScrollbarMode v_mode = mojom::blink::ScrollbarMode::kAuto;
- // Don't add auto scrollbars if the box contents aren't visible.
- if (GetLayoutBox()->HasAutoHorizontalScrollbar()) {
- if (option == kForbidAddingAutoBars)
- needs_horizontal_scrollbar &= HasHorizontalScrollbar();
- needs_horizontal_scrollbar &=
- GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
- VisibleContentRect(kIncludeScrollbars).Height();
- }
+ // First, determine what behavior the scrollbars say they should have.
+ {
+ if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+ // LayoutView is special as there's various quirks and settings that
+ // style doesn't account for.
+ layout_view->CalculateScrollbarModes(h_mode, v_mode);
+ } else {
+ auto overflow_x = GetLayoutBox()->StyleRef().OverflowX();
+ if (overflow_x == EOverflow::kScroll) {
+ h_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
+ } else if (overflow_x == EOverflow::kHidden ||
+ overflow_x == EOverflow::kVisible) {
+ h_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
+ }
+
+ auto overflow_y = GetLayoutBox()->StyleRef().OverflowY();
+ if (overflow_y == EOverflow::kScroll) {
+ v_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
+ } else if (overflow_y == EOverflow::kHidden ||
+ overflow_y == EOverflow::kVisible) {
+ v_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
+ }
+ }
- if (GetLayoutBox()->HasAutoVerticalScrollbar()) {
- if (option == kForbidAddingAutoBars)
- needs_vertical_scrollbar &= HasVerticalScrollbar();
- needs_vertical_scrollbar &= GetLayoutBox()->IsRooted() &&
- HasVerticalOverflow() &&
- VisibleContentRect(kIncludeScrollbars).Width();
+ // Since overlay scrollbars (the fade-in/out kind, not overflow: overlay)
+ // only appear when scrolling, we don't create them if there isn't overflow
+ // to scroll. Thus, overlay scrollbars can't be "always on". i.e.
+ // |overlay:scroll| behaves like |overlay:auto|.
+ bool has_custom_scrollbar_style =
+ ScrollbarStyleSource(*GetLayoutBox())
+ .StyleRef()
+ .HasPseudoElementStyle(kPseudoIdScrollbar);
+ bool will_be_overlay = GetPageScrollbarTheme().UsesOverlayScrollbars() &&
+ !has_custom_scrollbar_style;
+ if (will_be_overlay) {
+ if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
+ h_mode = mojom::blink::ScrollbarMode::kAuto;
+ if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
+ v_mode = mojom::blink::ScrollbarMode::kAuto;
+ }
}
- if (GetLayoutBox()->IsLayoutView()) {
- ScrollbarMode h_mode;
- ScrollbarMode v_mode;
- ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
+ // By default, don't make any changes.
+ needs_horizontal_scrollbar = HasHorizontalScrollbar();
+ needs_vertical_scrollbar = HasVerticalScrollbar();
- // Look for the scrollbarModes and reset the needs Horizontal & vertical
- // Scrollbar values based on scrollbarModes, as during force style change
- // StyleResolver::styleForDocument returns documentStyle with no overflow
- // values, due to which we are destroying the scrollbars that were already
- // present.
- if (h_mode == ScrollbarMode::kAlwaysOn)
+ // If the behavior doesn't depend on overflow or any other information, we
+ // can set it now.
+ {
+ if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
needs_horizontal_scrollbar = true;
- else if (h_mode == ScrollbarMode::kAlwaysOff)
+ else if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
needs_horizontal_scrollbar = false;
- if (v_mode == ScrollbarMode::kAlwaysOn)
+
+ if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
needs_vertical_scrollbar = true;
- else if (v_mode == ScrollbarMode::kAlwaysOff)
+ else if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
needs_vertical_scrollbar = false;
}
+
+ // If this is being performed before layout, we want to only update scrollbar
+ // existence if its based on purely style based reasons.
+ if (option == kOverflowIndependent)
+ return;
+
+ // If we have clean layout, we can make a decision on any scrollbars that
+ // depend on overflow.
+ {
+ if (h_mode == mojom::blink::ScrollbarMode::kAuto) {
+ // Don't add auto scrollbars if the box contents aren't visible.
+ needs_horizontal_scrollbar =
+ GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
+ VisibleContentRect(kIncludeScrollbars).Height();
+ }
+ if (v_mode == mojom::blink::ScrollbarMode::kAuto) {
+ needs_vertical_scrollbar = GetLayoutBox()->IsRooted() &&
+ HasVerticalOverflow() &&
+ VisibleContentRect(kIncludeScrollbars).Width();
+ }
+ }
}
bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
@@ -1584,11 +1642,12 @@ bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
if (!needs_horizontal_scrollbar && !needs_vertical_scrollbar)
return false;
- if (GetLayoutBox()->IsLayoutView()) {
- ScrollbarMode h_mode;
- ScrollbarMode v_mode;
- ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
- if (h_mode != ScrollbarMode::kAuto || v_mode != ScrollbarMode::kAuto)
+ if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+ mojom::blink::ScrollbarMode h_mode;
+ mojom::blink::ScrollbarMode v_mode;
+ layout_view->CalculateScrollbarModes(h_mode, v_mode);
+ if (h_mode != mojom::blink::ScrollbarMode::kAuto ||
+ v_mode != mojom::blink::ScrollbarMode::kAuto)
return false;
IntSize visible_size_with_scrollbars =
@@ -1738,6 +1797,29 @@ bool PaintLayerScrollableArea::SetTargetSnapAreaElementIds(
return false;
}
+bool PaintLayerScrollableArea::SnapContainerDataNeedsUpdate() const {
+ return RareData() ? RareData()->snap_container_data_needs_update_ : false;
+}
+
+void PaintLayerScrollableArea::SetSnapContainerDataNeedsUpdate(
+ bool needs_update) {
+ EnsureRareData().snap_container_data_needs_update_ = needs_update;
+ if (!needs_update)
+ return;
+ GetLayoutBox()
+ ->GetDocument()
+ .GetSnapCoordinator()
+ .SetAnySnapContainerDataNeedsUpdate(true);
+}
+
+bool PaintLayerScrollableArea::NeedsResnap() const {
+ return RareData() ? RareData()->needs_resnap_ : false;
+}
+
+void PaintLayerScrollableArea::SetNeedsResnap(bool needs_resnap) {
+ EnsureRareData().needs_resnap_ = needs_resnap;
+}
+
base::Optional<FloatPoint>
PaintLayerScrollableArea::GetSnapPositionAndSetTarget(
const cc::SnapSelectionStrategy& strategy) {
@@ -1779,21 +1861,17 @@ void PaintLayerScrollableArea::PositionOverflowControls() {
if (!HasOverflowControls())
return;
- const IntRect border_box =
- GetLayoutBox()->PixelSnappedBorderBoxRect(layer_->SubpixelAccumulation());
-
if (Scrollbar* vertical_scrollbar = VerticalScrollbar())
- vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar(border_box));
+ vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar());
if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
- horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar(border_box));
+ horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar());
if (scroll_corner_)
scroll_corner_->SetFrameRect(LayoutRect(ScrollCornerRect()));
if (resizer_)
- resizer_->SetFrameRect(
- LayoutRect(ResizerCornerRect(border_box, kResizerForPointer)));
+ resizer_->SetFrameRect(LayoutRect(ResizerCornerRect(kResizerForPointer)));
// FIXME, this should eventually be removed, once we are certain that
// composited controls get correctly positioned on a compositor update. For
@@ -1837,10 +1915,7 @@ bool PaintLayerScrollableArea::HitTestOverflowControls(
IntRect resize_control_rect;
if (GetLayoutBox()->StyleRef().HasResize()) {
- resize_control_rect =
- ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
- Layer()->SubpixelAccumulation()),
- kResizerForPointer);
+ resize_control_rect = ResizerCornerRect(kResizerForPointer);
if (resize_control_rect.Contains(local_point))
return true;
}
@@ -1850,14 +1925,13 @@ bool PaintLayerScrollableArea::HitTestOverflowControls(
if (HasVerticalScrollbar() &&
VerticalScrollbar()->ShouldParticipateInHitTesting()) {
- LayoutRect v_bar_rect(
- VerticalScrollbarStart(0, Layer()->PixelSnappedSize().Width()),
- GetLayoutBox()->BorderTop().ToInt(),
- VerticalScrollbar()->ScrollbarThickness(),
- visible_rect.Height() -
- (HasHorizontalScrollbar()
- ? HorizontalScrollbar()->ScrollbarThickness()
- : resize_control_size));
+ LayoutRect v_bar_rect(VerticalScrollbarStart(),
+ GetLayoutBox()->BorderTop().ToInt(),
+ VerticalScrollbar()->ScrollbarThickness(),
+ visible_rect.Height() -
+ (HasHorizontalScrollbar()
+ ? HorizontalScrollbar()->ScrollbarThickness()
+ : resize_control_size));
if (v_bar_rect.Contains(local_point)) {
result.SetScrollbar(VerticalScrollbar());
return true;
@@ -1870,7 +1944,7 @@ bool PaintLayerScrollableArea::HitTestOverflowControls(
// TODO(crbug.com/638981): Are the conversions to int intentional?
int h_scrollbar_thickness = HorizontalScrollbar()->ScrollbarThickness();
LayoutRect h_bar_rect(
- HorizontalScrollbarStart(0),
+ HorizontalScrollbarStart(),
GetLayoutBox()->BorderTop().ToInt() + visible_rect.Height() -
h_scrollbar_thickness,
visible_rect.Width() - (HasVerticalScrollbar()
@@ -1890,11 +1964,10 @@ bool PaintLayerScrollableArea::HitTestOverflowControls(
}
IntRect PaintLayerScrollableArea::ResizerCornerRect(
- const IntRect& bounds,
ResizerHitTestType resizer_hit_test_type) const {
if (!GetLayoutBox()->StyleRef().HasResize())
return IntRect();
- IntRect corner = CornerRect(bounds);
+ IntRect corner = CornerRect();
if (resizer_hit_test_type == kResizerForTouch) {
// We make the resizer virtually larger for touch hit testing. With the
@@ -1913,12 +1986,8 @@ IntRect PaintLayerScrollableArea::ResizerCornerRect(
IntRect PaintLayerScrollableArea::ScrollCornerAndResizerRect() const {
IntRect scroll_corner_and_resizer = ScrollCornerRect();
- if (scroll_corner_and_resizer.IsEmpty()) {
- scroll_corner_and_resizer =
- ResizerCornerRect(GetLayoutBox()->PixelSnappedBorderBoxRect(
- Layer()->SubpixelAccumulation()),
- kResizerForPointer);
- }
+ if (scroll_corner_and_resizer.IsEmpty())
+ return ResizerCornerRect(kResizerForPointer);
return scroll_corner_and_resizer;
}
@@ -1930,9 +1999,7 @@ bool PaintLayerScrollableArea::IsPointInResizeControl(
IntPoint local_point = RoundedIntPoint(
GetLayoutBox()->AbsoluteToLocalPoint(PhysicalOffset(absolute_point)));
- IntRect local_bounds(IntPoint(), Layer()->PixelSnappedSize());
- return ResizerCornerRect(local_bounds, resizer_hit_test_type)
- .Contains(local_point);
+ return ResizerCornerRect(resizer_hit_test_type).Contains(local_point);
}
bool PaintLayerScrollableArea::HitTestResizerInFragments(
@@ -1946,11 +2013,12 @@ bool PaintLayerScrollableArea::HitTestResizerInFragments(
for (int i = layer_fragments.size() - 1; i >= 0; --i) {
const PaintLayerFragment& fragment = layer_fragments.at(i);
- if (fragment.background_rect.Intersects(hit_test_location) &&
- ResizerCornerRect(PixelSnappedIntRect(fragment.layer_bounds),
- kResizerForPointer)
- .Contains(hit_test_location.RoundedPoint()))
- return true;
+ if (fragment.background_rect.Intersects(hit_test_location)) {
+ IntRect resizer_corner_rect = ResizerCornerRect(kResizerForPointer);
+ resizer_corner_rect.MoveBy(RoundedIntPoint(fragment.layer_bounds.offset));
+ if (resizer_corner_rect.Contains(hit_test_location.RoundedPoint()))
+ return true;
+ }
}
return false;
@@ -2002,12 +2070,10 @@ void PaintLayerScrollableArea::InvalidateAllStickyConstraints() {
}
void PaintLayerScrollableArea::InvalidateStickyConstraintsFor(
- PaintLayer* layer,
- bool needs_compositing_update) {
+ PaintLayer* layer) {
if (PaintLayerScrollableAreaRareData* d = RareData()) {
d->sticky_constraints_map_.erase(layer);
- if (needs_compositing_update &&
- layer->GetLayoutObject().StyleRef().HasStickyConstrainedPosition()) {
+ if (layer->GetLayoutObject().StyleRef().HasStickyConstrainedPosition()) {
layer->SetNeedsCompositingInputsUpdate();
layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
}
@@ -2037,7 +2103,7 @@ IntSize PaintLayerScrollableArea::OffsetFromResizeCorner(
// left corner.
// FIXME: This assumes the location is 0, 0. Is this guaranteed to always be
// the case?
- IntSize element_size = Layer()->PixelSnappedSize();
+ IntSize element_size = PixelSnappedBorderBoxSize();
if (GetLayoutBox()->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
element_size.SetWidth(0);
IntPoint resizer_point = IntPoint(element_size);
@@ -2143,15 +2209,15 @@ void PaintLayerScrollableArea::Resize(const IntPoint& pos,
CSSPrimitiveValue::UnitType::kPixels);
}
- document.UpdateStyleAndLayout();
+ document.UpdateStyleAndLayout(DocumentUpdateReason::kSizeChange);
- // FIXME (Radar 4118564): We should also autoscroll the window as necessary to
+ // FIXME: We should also autoscroll the window as necessary to
// keep the point under the cursor in view.
}
PhysicalRect PaintLayerScrollableArea::ScrollIntoView(
const PhysicalRect& absolute_rect,
- const WebScrollIntoViewParams& params) {
+ const mojom::blink::ScrollIntoViewParamsPtr& params) {
PhysicalRect local_expose_rect =
GetLayoutBox()->AbsoluteToLocalRect(absolute_rect);
PhysicalOffset border_origin_to_scroll_origin(-GetLayoutBox()->BorderLeft(),
@@ -2168,13 +2234,13 @@ PhysicalRect PaintLayerScrollableArea::ScrollIntoView(
PhysicalRect scroll_snapport_rect = VisibleScrollSnapportRect();
ScrollOffset target_offset = ScrollAlignment::GetScrollOffsetToExpose(
- scroll_snapport_rect, local_expose_rect, params.GetScrollAlignmentX(),
- params.GetScrollAlignmentY(), GetScrollOffset());
+ scroll_snapport_rect, local_expose_rect, *params->align_x.get(),
+ *params->align_y.get(), GetScrollOffset());
ScrollOffset new_scroll_offset(
ClampScrollOffset(RoundedIntSize(target_offset)));
ScrollOffset old_scroll_offset = GetScrollOffset();
- if (params.GetScrollType() == kUserScroll) {
+ if (params->type == mojom::blink::ScrollType::kUser) {
if (!UserInputScrollable(kHorizontalScrollbar))
new_scroll_offset.SetWidth(old_scroll_offset.Width());
if (!UserInputScrollable(kVerticalScrollbar))
@@ -2188,17 +2254,16 @@ PhysicalRect PaintLayerScrollableArea::ScrollIntoView(
end_point = GetSnapPositionAndSetTarget(*strategy).value_or(end_point);
new_scroll_offset = ScrollPositionToOffset(end_point);
- if (params.is_for_scroll_sequence) {
- DCHECK(params.GetScrollType() == kProgrammaticScroll ||
- params.GetScrollType() == kUserScroll);
- ScrollBehavior behavior =
- DetermineScrollBehavior(params.GetScrollBehavior(),
- GetLayoutBox()->StyleRef().GetScrollBehavior());
+ if (params->is_for_scroll_sequence) {
+ DCHECK(params->type == mojom::blink::ScrollType::kProgrammatic ||
+ params->type == mojom::blink::ScrollType::kUser);
+ mojom::blink::ScrollBehavior behavior = DetermineScrollBehavior(
+ params->behavior, GetLayoutBox()->StyleRef().GetScrollBehavior());
GetSmoothScrollSequencer()->QueueAnimation(this, new_scroll_offset,
behavior);
} else {
- SetScrollOffset(new_scroll_offset, params.GetScrollType(),
- kScrollBehaviorInstant);
+ SetScrollOffset(new_scroll_offset, params->type,
+ mojom::blink::ScrollBehavior::kInstant);
}
ScrollOffset scroll_offset_difference = new_scroll_offset - old_scroll_offset;
@@ -2239,12 +2304,12 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
bool is_visible_to_hit_test =
GetLayoutBox()->StyleRef().VisibleToHitTesting();
bool did_scroll_overflow = scrolls_overflow_;
- if (GetLayoutBox()->IsLayoutView()) {
- ScrollbarMode h_mode;
- ScrollbarMode v_mode;
- ToLayoutView(GetLayoutBox())->CalculateScrollbarModes(h_mode, v_mode);
- if (h_mode == ScrollbarMode::kAlwaysOff &&
- v_mode == ScrollbarMode::kAlwaysOff)
+ if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+ mojom::blink::ScrollbarMode h_mode;
+ mojom::blink::ScrollbarMode v_mode;
+ layout_view->CalculateScrollbarModes(h_mode, v_mode);
+ if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOff &&
+ v_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
has_overflow = false;
}
@@ -2264,7 +2329,7 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() &&
scrolls_overflow_) {
- if (GetLayoutBox()->IsLayoutView()) {
+ if (IsA<LayoutView>(GetLayoutBox())) {
if (Element* owner = GetLayoutBox()->GetDocument().LocalOwner()) {
owner->GetDocument().GetRootScrollerController().ConsiderForImplicit(
*owner);
@@ -2281,8 +2346,8 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
// PaintPropertyTreeBuilder::updateScrollAndScrollTranslation).
GetLayoutBox()->SetNeedsPaintPropertyUpdate();
- // Scroll hit test display items depend on whether the box scrolls overflow.
- // The scroll hit test display items paint in the background phase
+ // Scroll hit test data depend on whether the box scrolls overflow.
+ // They are painted in the background phase
// (see: BoxPainter::PaintBoxDecorationBackground).
GetLayoutBox()->SetBackgroundNeedsFullPaintInvalidation();
@@ -2290,16 +2355,18 @@ void PaintLayerScrollableArea::UpdateScrollableAreaSet() {
}
void PaintLayerScrollableArea::UpdateCompositingLayersAfterScroll() {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+
PaintLayerCompositor* compositor = GetLayoutBox()->View()->Compositor();
- if (!compositor->InCompositingMode())
+ if (!compositor || !compositor->InCompositingMode())
return;
if (UsesCompositedScrolling()) {
DCHECK(Layer()->HasCompositedLayerMapping());
ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator();
- bool handled_scroll =
- scrolling_coordinator &&
- scrolling_coordinator->UpdateCompositedScrollOffset(this);
+ bool handled_scroll = scrolling_coordinator &&
+ scrolling_coordinator->UpdateCompositorScrollOffset(
+ *GetLayoutBox()->GetFrame(), *this);
if (!handled_scroll) {
compositor->SetNeedsCompositingUpdate(
@@ -2309,15 +2376,18 @@ void PaintLayerScrollableArea::UpdateCompositingLayersAfterScroll() {
// If we have fixed elements and we scroll the root layer we might
// change compositing since the fixed elements might now overlap a
// composited layer.
- if (Layer()->IsRootLayer()) {
- LocalFrame* frame = GetLayoutBox()->GetFrame();
- if (frame && frame->View() &&
- frame->View()->HasViewportConstrainedObjects()) {
- Layer()->SetNeedsCompositingInputsUpdate();
+ if (!base::FeatureList::IsEnabled(
+ features::kAssumeOverlapAfterFixedOrStickyPosition)) {
+ if (Layer()->IsRootLayer()) {
+ LocalFrame* frame = GetLayoutBox()->GetFrame();
+ if (frame && frame->View() &&
+ frame->View()->HasViewportConstrainedObjects()) {
+ Layer()->SetNeedsCompositingInputsUpdate();
+ }
}
}
} else {
- Layer()->SetNeedsCompositingInputsUpdate();
+ Layer()->SetNeedsCompositingInputsUpdate(false);
}
}
@@ -2385,7 +2455,29 @@ bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
: DocumentLifecycle::kInCompositingUpdate,
GetDocument()->Lifecycle().GetState());
+ const auto* box = GetLayoutBox();
+ auto old_background_paint_location = box->GetBackgroundPaintLocation();
non_composited_main_thread_scrolling_reasons_ = 0;
+ auto new_background_paint_location =
+ box->ComputeBackgroundPaintLocationIfComposited(
+ &non_composited_main_thread_scrolling_reasons_);
+ bool needs_composited_scrolling = ComputeNeedsCompositedScrollingInternal(
+ new_background_paint_location, force_prefer_compositing_to_lcd_text);
+ if (!needs_composited_scrolling)
+ new_background_paint_location = kBackgroundPaintInGraphicsLayer;
+ if (new_background_paint_location != old_background_paint_location) {
+ box->GetMutableForPainting().SetBackgroundPaintLocation(
+ new_background_paint_location);
+ }
+
+ return needs_composited_scrolling;
+}
+
+bool PaintLayerScrollableArea::ComputeNeedsCompositedScrollingInternal(
+ BackgroundPaintLocation background_paint_location_if_composited,
+ bool force_prefer_compositing_to_lcd_text) {
+ DCHECK_EQ(background_paint_location_if_composited,
+ GetLayoutBox()->ComputeBackgroundPaintLocationIfComposited());
if (CompositingReasonFinder::RequiresCompositingForRootScroller(*layer_))
return true;
@@ -2419,15 +2511,16 @@ bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
// transforms are also integer.
bool background_supports_lcd_text =
box->StyleRef().IsStackingContext() &&
- (box->GetBackgroundPaintLocation(
- &non_composited_main_thread_scrolling_reasons_) &
+ (background_paint_location_if_composited &
kBackgroundPaintInScrollingContents) &&
layer_->BackgroundIsKnownToBeOpaqueInRect(box->PhysicalPaddingBoxRect(),
true) &&
!layer_->CompositesWithTransform() && !layer_->CompositesWithOpacity();
if (!force_prefer_compositing_to_lcd_text &&
- !layer_->Compositor()->PreferCompositingToLCDTextEnabled() &&
+ !box->GetDocument()
+ .GetSettings()
+ ->GetPreferCompositingToLCDTextEnabled() &&
!background_supports_lcd_text) {
if (layer_->CompositesWithOpacity()) {
non_composited_main_thread_scrolling_reasons_ |=
@@ -2511,12 +2604,13 @@ PaintLayerScrollableArea::GetCompositorAnimationTimeline() const {
}
bool PaintLayerScrollableArea::HasTickmarks() const {
- return layer_->IsRootLayer() && ToLayoutView(GetLayoutBox())->HasTickmarks();
+ return layer_->IsRootLayer() &&
+ To<LayoutView>(GetLayoutBox())->HasTickmarks();
}
Vector<IntRect> PaintLayerScrollableArea::GetTickmarks() const {
if (layer_->IsRootLayer())
- return ToLayoutView(GetLayoutBox())->GetTickmarks();
+ return To<LayoutView>(GetLayoutBox())->GetTickmarks();
return Vector<IntRect>();
}
@@ -2571,7 +2665,7 @@ Scrollbar* PaintLayerScrollableArea::ScrollbarManager::CreateScrollbar(
style_source.StyleRef().HasPseudoElementStyle(kPseudoIdScrollbar);
if (has_custom_scrollbar_style) {
DCHECK(style_source.GetNode() && style_source.GetNode()->IsElementNode());
- scrollbar = CustomScrollbar::CreateCustomScrollbar(
+ scrollbar = MakeGarbageCollected<CustomScrollbar>(
ScrollableArea(), orientation, To<Element>(style_source.GetNode()));
} else {
ScrollbarControlSize scrollbar_size = kRegularScrollbar;
@@ -2580,7 +2674,7 @@ Scrollbar* PaintLayerScrollableArea::ScrollbarManager::CreateScrollbar(
style_source.StyleRef().EffectiveAppearance());
}
Element* style_source_element = nullptr;
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (::features::IsFormControlsRefreshEnabled()) {
style_source_element = DynamicTo<Element>(style_source.GetNode());
}
scrollbar = MakeGarbageCollected<Scrollbar>(
@@ -2832,8 +2926,13 @@ static IntRect InvalidatePaintOfScrollbarIfNeeded(
bool is_overlay = scrollbar && scrollbar->IsOverlayScrollbar();
IntRect new_visual_rect;
- if (scrollbar)
+ if (scrollbar) {
new_visual_rect = scrollbar->FrameRect();
+ // TODO(crbug.com/1020913): We should not round paint_offset but should
+ // consider subpixel accumulation when painting scrollbars.
+ new_visual_rect.MoveBy(
+ RoundedIntPoint(context.fragment_data->PaintOffset()));
+ }
if (needs_paint_invalidation && graphics_layer) {
// If the scrollbar needs paint invalidation but didn't change location/size
@@ -2906,8 +3005,10 @@ void PaintLayerScrollableArea::InvalidatePaintOfScrollControlsIfNeeded(
box_geometry_has_been_invalidated, context));
IntRect scroll_corner_and_resizer_visual_rect = ScrollCornerAndResizerRect();
+ // TODO(crbug.com/1020913): We should not round paint_offset but should
+ // consider subpixel accumulation when painting scrollbars.
scroll_corner_and_resizer_visual_rect.MoveBy(
- RoundedIntPoint(box.FirstFragment().PaintOffset()));
+ RoundedIntPoint(context.fragment_data->PaintOffset()));
if (ScrollControlNeedsPaintInvalidation(
scroll_corner_and_resizer_visual_rect,
scroll_corner_and_resizer_visual_rect_,
@@ -3020,10 +3121,21 @@ CompositorElementId PaintLayerScrollableArea::GetScrollElementId() const {
GetLayoutBox()->UniqueId(), CompositorElementIdNamespace::kScroll);
}
+IntSize PaintLayerScrollableArea::PixelSnappedBorderBoxSize() const {
+ // TODO(crbug.com/1020913): We use this method during
+ // PositionOverflowControls() even before the paint offset is updated.
+ // This can be fixed only after we support subpixels in overflow control
+ // geometry. For now we ensure correct pixel snapping of overflow controls by
+ // calling PositionOverflowControls() again when paint offset is updated.
+ return GetLayoutBox()->PixelSnappedBorderBoxSize(
+ GetLayoutBox()->FirstFragment().PaintOffset());
+}
+
IntRect
PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::VisualRect()
const {
const auto* box = scrollable_area_->GetLayoutBox();
+
const auto& paint_offset = box->FirstFragment().PaintOffset();
auto overflow_clip_rect =
PixelSnappedIntRect(box->OverflowClipRect(paint_offset));
@@ -3037,6 +3149,30 @@ PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::VisualRect()
scrollable_area_->layer_->GraphicsLayerBacking()->VisualRect());
}
#endif
+
+ // The HTML element of a document is special, in that it can have a transform,
+ // but the bounds of the painted area of the element still extends beyond
+ // its actual size to encompass the entire viewport canvas. This is
+ // accomplished in ViewPainter by starting with a rect in viewport canvas
+ // space that is equal to the size of the viewport canvas, then mapping it
+ // into the local border box space of the HTML element, and painting a rect
+ // equal to the bounding box of the result. We need to add in that mapped rect
+ // in such cases.
+ const Document& document = box->GetDocument();
+ if (IsA<LayoutView>(box) &&
+ (document.IsXMLDocument() || document.IsHTMLDocument())) {
+ if (const auto* document_element = document.documentElement()) {
+ if (const auto* document_element_object =
+ document_element->GetLayoutObject()) {
+ TransformationMatrix matrix;
+ document_element_object->GetTransformFromContainer(
+ box, PhysicalOffset(), matrix);
+ if (matrix.IsInvertible())
+ result.Unite(matrix.Inverse().MapRect(result));
+ }
+ }
+ }
+
return result;
}
@@ -3054,12 +3190,6 @@ PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::OwnerNodeId()
->OwnerNodeId();
}
-bool PaintLayerScrollableArea::ScrollingBackgroundDisplayItemClient::
- PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- return scrollable_area_->GetLayoutBox()
- ->PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
-}
-
IntRect PaintLayerScrollableArea::ScrollCornerDisplayItemClient::VisualRect()
const {
return scrollable_area_->scroll_corner_and_resizer_visual_rect_;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index c5a4495f359..afe17a03130 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -46,6 +46,7 @@
#include <memory>
#include "base/macros.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/scroll_anchor.h"
#include "third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h"
@@ -77,6 +78,8 @@ struct CORE_EXPORT PaintLayerScrollableAreaRareData {
StickyConstraintsMap sticky_constraints_map_;
base::Optional<cc::SnapContainerData> snap_container_data_;
+ bool snap_container_data_needs_update_ = true;
+ bool needs_resnap_ = false;
DISALLOW_COPY_AND_ASSIGN(PaintLayerScrollableAreaRareData);
};
@@ -162,7 +165,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
void DestroyDetachedScrollbars();
void Dispose();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
Scrollbar* CreateScrollbar(ScrollbarOrientation);
@@ -246,10 +249,6 @@ class CORE_EXPORT PaintLayerScrollableArea final
// FIXME: We should pass in the LayoutBox but this opens a window
// for crashers during PaintLayer setup (see crbug.com/368062).
- static PaintLayerScrollableArea* Create(PaintLayer& layer) {
- return MakeGarbageCollected<PaintLayerScrollableArea>(layer);
- }
-
explicit PaintLayerScrollableArea(PaintLayer&);
~PaintLayerScrollableArea() override;
@@ -345,7 +344,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
bool UserInputScrollable(ScrollbarOrientation) const override;
bool ShouldPlaceVerticalScrollbarOnLeft() const override;
int PageStep(ScrollbarOrientation) const override;
- ScrollBehavior ScrollBehaviorStyle() const override;
+ mojom::blink::ScrollBehavior ScrollBehaviorStyle() const override;
WebColorScheme UsedColorScheme() const override;
cc::AnimationHost* GetCompositorAnimationHost() const override;
CompositorAnimationTimeline* GetCompositorAnimationTimeline() const override;
@@ -358,22 +357,25 @@ class CORE_EXPORT PaintLayerScrollableArea final
IntPoint ScrollOrigin() const { return scroll_origin_; }
bool ScrollOriginChanged() const { return scroll_origin_changed_; }
- void ScrollToAbsolutePosition(
- const FloatPoint& position,
- ScrollBehavior scroll_behavior = kScrollBehaviorInstant,
- ScrollType scroll_type = kProgrammaticScroll) {
+ void ScrollToAbsolutePosition(const FloatPoint& position,
+ mojom::blink::ScrollBehavior scroll_behavior =
+ mojom::blink::ScrollBehavior::kInstant,
+ mojom::blink::ScrollType scroll_type =
+ mojom::blink::ScrollType::kProgrammatic) {
SetScrollOffset(position - ScrollOrigin(), scroll_type, scroll_behavior);
}
// This will set the scroll position without clamping, and it will do all
// post-update work even if the scroll position didn't change.
- void SetScrollOffsetUnconditionally(const ScrollOffset&,
- ScrollType = kProgrammaticScroll);
+ void SetScrollOffsetUnconditionally(
+ const ScrollOffset&,
+ mojom::blink::ScrollType = mojom::blink::ScrollType::kProgrammatic);
// This will set the scroll position without clamping, and it will do all
// post-update work even if the scroll position didn't change.
- void SetScrollPositionUnconditionally(const DoublePoint&,
- ScrollType = kProgrammaticScroll);
+ void SetScrollPositionUnconditionally(
+ const DoublePoint&,
+ mojom::blink::ScrollType = mojom::blink::ScrollType::kProgrammatic);
// TODO(szager): Actually run these after all of layout is finished.
// Currently, they run at the end of box()'es layout (or after all flexbox
@@ -439,8 +441,9 @@ class CORE_EXPORT PaintLayerScrollableArea final
// Returns the new offset, after scrolling, of the given rect in absolute
// coordinates, clipped by the parent's client rect.
- PhysicalRect ScrollIntoView(const PhysicalRect&,
- const WebScrollIntoViewParams&) override;
+ PhysicalRect ScrollIntoView(
+ const PhysicalRect&,
+ const mojom::blink::ScrollIntoViewParamsPtr&) override;
// Returns true if scrollable area is in the FrameView's collection of
// scrollable areas. This can only happen if we're scrollable, visible to hit
@@ -452,6 +455,8 @@ class CORE_EXPORT PaintLayerScrollableArea final
// Rectangle encompassing the scroll corner and resizer rect.
IntRect ScrollCornerAndResizerRect() const;
+ // This also updates main thread scrolling reasons and the LayoutBox's
+ // background paint location.
bool ComputeNeedsCompositedScrolling(
bool force_prefer_compositing_to_lcd_text);
@@ -463,14 +468,14 @@ class CORE_EXPORT PaintLayerScrollableArea final
return needs_composited_scrolling_;
}
- IntRect ResizerCornerRect(const IntRect&, ResizerHitTestType) const;
+ IntRect ResizerCornerRect(ResizerHitTestType) const;
PaintLayer* Layer() const override;
LayoutCustomScrollbarPart* Resizer() const { return resizer_; }
- IntRect RectForHorizontalScrollbar(const IntRect& border_box_rect) const;
- IntRect RectForVerticalScrollbar(const IntRect& border_box_rect) const;
+ IntRect RectForHorizontalScrollbar() const;
+ IntRect RectForVerticalScrollbar() const;
bool ScheduleAnimation() override;
bool ShouldPerformScrollAnchoring() const override;
@@ -527,8 +532,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
}
void InvalidateAllStickyConstraints();
- void InvalidateStickyConstraintsFor(PaintLayer*,
- bool needs_compositing_update = true);
+ void InvalidateStickyConstraintsFor(PaintLayer*);
void InvalidatePaintForStickyDescendants();
uint32_t GetNonCompositedMainThreadScrollingReasons() {
return non_composited_main_thread_scrolling_reasons_;
@@ -562,7 +566,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
bool HasHorizontalOverflow() const;
bool HasVerticalOverflow() const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
const DisplayItemClient& GetScrollingBackgroundDisplayItemClient() const {
return scrolling_background_display_item_client_;
@@ -574,12 +578,30 @@ class CORE_EXPORT PaintLayerScrollableArea final
const cc::SnapContainerData* GetSnapContainerData() const override;
void SetSnapContainerData(base::Optional<cc::SnapContainerData>) override;
bool SetTargetSnapAreaElementIds(cc::TargetSnapAreaElementIds) override;
+ bool SnapContainerDataNeedsUpdate() const override;
+ void SetSnapContainerDataNeedsUpdate(bool) override;
+ bool NeedsResnap() const override;
+ void SetNeedsResnap(bool) override;
base::Optional<FloatPoint> GetSnapPositionAndSetTarget(
const cc::SnapSelectionStrategy& strategy) override;
void DisposeImpl() override;
+ void SetPendingHistoryRestoreScrollOffset(
+ const HistoryItem::ViewState& view_state,
+ bool should_restore_scroll) override {
+ if (!should_restore_scroll)
+ return;
+ pending_view_state_ = view_state;
+ }
+
+ void ApplyPendingHistoryRestoreScrollOffset() override;
+
+ bool HasPendingHistoryRestoreScrollOffset() override {
+ return !!pending_view_state_;
+ }
+
private:
bool NeedsScrollbarReconstruction() const;
@@ -591,18 +613,29 @@ class CORE_EXPORT PaintLayerScrollableArea final
// Update the proportions used for thumb rect dimensions.
void UpdateScrollbarProportions();
- void UpdateScrollOffset(const ScrollOffset&, ScrollType) override;
+ void UpdateScrollOffset(const ScrollOffset&,
+ mojom::blink::ScrollType) override;
void InvalidatePaintForScrollOffsetChange();
- int VerticalScrollbarStart(int min_x, int max_x) const;
- int HorizontalScrollbarStart(int min_x) const;
+ int VerticalScrollbarStart() const;
+ int HorizontalScrollbarStart() const;
IntSize ScrollbarOffset(const Scrollbar&) const;
- enum ComputeScrollbarExistenceOption { kDefault, kForbidAddingAutoBars };
+ // If OverflowIndependent is specified, will only change current scrollbar
+ // existence if the new style doesn't depend on overflow which requires
+ // layout to be clean. It'd be nice if we could always determine existence at
+ // one point, after layout. Unfortunately, it seems that parts of layout are
+ // dependent on scrollbar existence in cases like |overflow:scroll|, removing
+ // the post style pass causes breaks in tests e.g. forms web_tests. Thus, we
+ // must do two scrollbar existence passes.
+ enum ComputeScrollbarExistenceOption {
+ kDependsOnOverflow,
+ kOverflowIndependent
+ };
void ComputeScrollbarExistence(
bool& needs_horizontal_scrollbar,
bool& needs_vertical_scrollbar,
- ComputeScrollbarExistenceOption = kDefault) const;
+ ComputeScrollbarExistenceOption = kDependsOnOverflow) const;
// If the content fits entirely in the area without auto scrollbars, returns
// true to try to remove them. This is a heuristic and can be incorrect if the
@@ -637,7 +670,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
return *rare_data_.get();
}
- IntRect CornerRect(const IntRect& bounds) const;
+ IntRect CornerRect() const;
void ScrollControlWasSetNeedsPaintInvalidation() override;
@@ -647,6 +680,13 @@ class CORE_EXPORT PaintLayerScrollableArea final
bool HasNonCompositedStickyDescendants() const;
+ IntSize PixelSnappedBorderBoxSize() const;
+
+ using BackgroundPaintLocation = uint8_t;
+ bool ComputeNeedsCompositedScrollingInternal(
+ BackgroundPaintLocation background_paint_location_if_composited,
+ bool force_prefer_compositing_to_lcd_text);
+
// PaintLayer is destructed before PaintLayerScrollable area, during this
// time before PaintLayerScrollableArea has been collected layer_ will
// be set to nullptr by the Dispose method.
@@ -672,6 +712,7 @@ class CORE_EXPORT PaintLayerScrollableArea final
// instance has been reconstructed.
unsigned rebuild_horizontal_scrollbar_layer_ : 1;
unsigned rebuild_vertical_scrollbar_layer_ : 1;
+ unsigned previous_vertical_scrollbar_on_left_ : 1;
unsigned needs_scroll_offset_clamp_ : 1;
unsigned needs_relayout_ : 1;
@@ -742,7 +783,6 @@ class CORE_EXPORT PaintLayerScrollableArea final
IntRect VisualRect() const final;
String DebugName() const final;
DOMNodeId OwnerNodeId() const final;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const final;
Member<const PaintLayerScrollableArea> scrollable_area_;
};
@@ -768,14 +808,9 @@ class CORE_EXPORT PaintLayerScrollableArea final
ScrollingBackgroundDisplayItemClient
scrolling_background_display_item_client_{*this};
ScrollCornerDisplayItemClient scroll_corner_display_item_client_{*this};
+ base::Optional<HistoryItem::ViewState> pending_view_state_;
};
-DEFINE_TYPE_CASTS(PaintLayerScrollableArea,
- ScrollableArea,
- scrollableArea,
- scrollableArea->IsPaintLayerScrollableArea(),
- scrollableArea.IsPaintLayerScrollableArea());
-
} // namespace blink
#endif // LayerScrollableArea_h
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
index 70a2bd4c2e0..da749e252a3 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_scrollable_area_test.cc
@@ -8,8 +8,11 @@
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
+#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
+#include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
@@ -677,14 +680,16 @@ TEST_P(PaintLayerScrollableAreaTest, HideTooltipWhenScrollPositionChanges) {
EXPECT_CALL(GetChromeClient(),
MockSetToolTip(GetDocument().GetFrame(), String(), _))
.Times(1);
- scrollable_area->SetScrollOffset(ScrollOffset(1, 1), kUserScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(1, 1),
+ mojom::blink::ScrollType::kUser);
// Programmatic scrolling should not dismiss the tooltip, so setToolTip
// should not be called for this invocation.
EXPECT_CALL(GetChromeClient(),
MockSetToolTip(GetDocument().GetFrame(), String(), _))
.Times(0);
- scrollable_area->SetScrollOffset(ScrollOffset(2, 2), kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(2, 2),
+ mojom::blink::ScrollType::kProgrammatic);
}
TEST_P(PaintLayerScrollableAreaTest, IncludeOverlayScrollbarsInVisibleWidth) {
@@ -703,7 +708,8 @@ TEST_P(PaintLayerScrollableAreaTest, IncludeOverlayScrollbarsInVisibleWidth) {
PaintLayerScrollableArea* scrollable_area =
ToLayoutBoxModelObject(scroller->GetLayoutObject())->GetScrollableArea();
ASSERT_TRUE(scrollable_area);
- scrollable_area->SetScrollOffset(ScrollOffset(100, 0), kClampingScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(100, 0),
+ mojom::blink::ScrollType::kClamping);
EXPECT_EQ(scrollable_area->GetScrollOffset().Width(), 0);
}
@@ -819,7 +825,8 @@ TEST_P(PaintLayerScrollableAreaTest, OverflowHiddenScrollOffsetInvalidation) {
// Going from zero scroll offset to non-zero may require a new paint property
// and should invalidate paint and paint properties.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(scroller->PaintingLayer()->SelfNeedsRepaint());
EXPECT_TRUE(scroller->NeedsPaintPropertyUpdate());
UpdateAllLifecyclePhasesForTest();
@@ -829,7 +836,8 @@ TEST_P(PaintLayerScrollableAreaTest, OverflowHiddenScrollOffsetInvalidation) {
EXPECT_NE(nullptr, properties->ScrollTranslation());
// A property update is needed when scroll offset changes.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 2), kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 2),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(scroller->NeedsPaintPropertyUpdate());
UpdateAllLifecyclePhasesForTest();
@@ -839,7 +847,8 @@ TEST_P(PaintLayerScrollableAreaTest, OverflowHiddenScrollOffsetInvalidation) {
// Going from non-zero scroll offset to zero may require destroying a paint
// property and should invalidate paint and paint properties.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 0), kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 0),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(scroller->PaintingLayer()->SelfNeedsRepaint());
EXPECT_TRUE(scroller->NeedsPaintPropertyUpdate());
UpdateAllLifecyclePhasesForTest();
@@ -873,7 +882,8 @@ TEST_P(PaintLayerScrollableAreaTest, ScrollDoesNotInvalidate) {
EXPECT_EQ(FloatSize(0, 0), scrollable_area->GetScrollOffset());
// Changing the scroll offset should not require paint invalidation.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_FALSE(scroller->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(scroller->NeedsPaintPropertyUpdate());
UpdateAllLifecyclePhasesForTest();
@@ -901,19 +911,17 @@ TEST_P(PaintLayerScrollableAreaTest,
auto* scroller = ToLayoutBox(GetLayoutObjectByElementId("scroller"));
auto* scrollable_area = scroller->GetScrollableArea();
EXPECT_EQ(kBackgroundPaintInScrollingContents,
+ scroller->ComputeBackgroundPaintLocationIfComposited());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
scroller->GetBackgroundPaintLocation());
// Programmatically changing the scroll offset.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // No invalidation because the background paints into scrolling contents.
- EXPECT_FALSE(scroller->ShouldDoFullPaintInvalidation());
- EXPECT_FALSE(scroller->BackgroundNeedsFullPaintInvalidation());
- } else {
- // Full invalidation because there is no separate scrolling contents layer.
- EXPECT_TRUE(scroller->ShouldDoFullPaintInvalidation());
- EXPECT_TRUE(scroller->BackgroundNeedsFullPaintInvalidation());
- }
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
+ // Full invalidation because there is no separate scrolling contents layer.
+ EXPECT_TRUE(scroller->ShouldDoFullPaintInvalidation());
+ EXPECT_TRUE(scroller->BackgroundNeedsFullPaintInvalidation());
+
EXPECT_TRUE(scroller->NeedsPaintPropertyUpdate());
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(FloatSize(0, 1), scrollable_area->GetScrollOffset());
@@ -942,10 +950,13 @@ TEST_P(PaintLayerScrollableAreaTest,
auto* scrollable_area = scroller->GetScrollableArea();
EXPECT_EQ(
kBackgroundPaintInGraphicsLayer | kBackgroundPaintInScrollingContents,
- scroller->GetBackgroundPaintLocation());
+ scroller->ComputeBackgroundPaintLocationIfComposited());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
+ scroller->GetBackgroundPaintLocation());
// Programmatically changing the scroll offset.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
// No invalidation because the background paints into the main layer.
EXPECT_TRUE(scroller->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(scroller->BackgroundNeedsFullPaintInvalidation());
@@ -985,8 +996,8 @@ TEST_P(PaintLayerScrollableAreaTest, ViewScrollWithFixedAttachmentBackground) {
// Programmatically changing the view's scroll offset. Should invalidate all
// objects with fixed attachment background.
- view_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
- kProgrammaticScroll);
+ view_scrollable_area->SetScrollOffset(
+ ScrollOffset(0, 1), mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_FALSE(fixed_background_div->NeedsPaintPropertyUpdate());
@@ -997,13 +1008,14 @@ TEST_P(PaintLayerScrollableAreaTest, ViewScrollWithFixedAttachmentBackground) {
// Programmatically changing the div's scroll offset. Should invalidate the
// scrolled div with fixed attachment background.
- div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+ div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->NeedsPaintPropertyUpdate());
EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
- EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+ EXPECT_FALSE(GetLayoutView().NeedsPaintPropertyUpdate());
}
TEST_P(PaintLayerScrollableAreaTest,
@@ -1032,14 +1044,16 @@ TEST_P(PaintLayerScrollableAreaTest,
auto* fixed_background_div =
ToLayoutBox(GetLayoutObjectByElementId("fixed-background"));
EXPECT_EQ(kBackgroundPaintInScrollingContents,
+ fixed_background_div->ComputeBackgroundPaintLocationIfComposited());
+ EXPECT_EQ(kBackgroundPaintInGraphicsLayer,
fixed_background_div->GetBackgroundPaintLocation());
auto* div_scrollable_area = fixed_background_div->GetScrollableArea();
auto* view_scrollable_area = GetLayoutView().GetScrollableArea();
// Programmatically changing the view's scroll offset. Should invalidate all
// objects with fixed attachment background.
- view_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
- kProgrammaticScroll);
+ view_scrollable_area->SetScrollOffset(
+ ScrollOffset(0, 1), mojom::blink::ScrollType::kProgrammatic);
EXPECT_FALSE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_FALSE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_FALSE(fixed_background_div->NeedsPaintPropertyUpdate());
@@ -1050,13 +1064,14 @@ TEST_P(PaintLayerScrollableAreaTest,
// Programmatically changing the div's scroll offset. Should invalidate the
// scrolled div with fixed attachment background.
- div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+ div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_FALSE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_FALSE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->NeedsPaintPropertyUpdate());
EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
- EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+ EXPECT_FALSE(GetLayoutView().NeedsPaintPropertyUpdate());
}
TEST_P(PaintLayerScrollableAreaTest,
@@ -1091,8 +1106,8 @@ TEST_P(PaintLayerScrollableAreaTest,
// Programmatically changing the view's scroll offset. Should invalidate all
// objects with fixed attachment background except the layout view.
- view_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
- kProgrammaticScroll);
+ view_scrollable_area->SetScrollOffset(
+ ScrollOffset(0, 1), mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_FALSE(fixed_background_div->NeedsPaintPropertyUpdate());
@@ -1103,13 +1118,14 @@ TEST_P(PaintLayerScrollableAreaTest,
// Programmatically changing the div's scroll offset. Should invalidate the
// scrolled div with fixed attachment background.
- div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1), kProgrammaticScroll);
+ div_scrollable_area->SetScrollOffset(ScrollOffset(0, 1),
+ mojom::blink::ScrollType::kProgrammatic);
EXPECT_TRUE(fixed_background_div->ShouldDoFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->BackgroundNeedsFullPaintInvalidation());
EXPECT_TRUE(fixed_background_div->NeedsPaintPropertyUpdate());
EXPECT_FALSE(GetLayoutView().ShouldDoFullPaintInvalidation());
EXPECT_FALSE(GetLayoutView().BackgroundNeedsFullPaintInvalidation());
- EXPECT_TRUE(GetLayoutView().NeedsPaintPropertyUpdate());
+ EXPECT_FALSE(GetLayoutView().NeedsPaintPropertyUpdate());
}
TEST_P(PaintLayerScrollableAreaTest, HitTestOverlayScrollbars) {
@@ -1179,7 +1195,8 @@ TEST_P(PaintLayerScrollableAreaTest, CompositedStickyDescendant) {
.Transform()
.IsIdentity());
- scrollable_area->SetScrollOffset(ScrollOffset(0, 50), kUserScroll);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 50),
+ mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(FloatSize(0, 50), sticky->FirstFragment()
@@ -1233,7 +1250,8 @@ TEST_P(PaintLayerScrollableAreaTest, ScrollbarMaximum) {
PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
Scrollbar* scrollbar = scrollable_area->VerticalScrollbar();
- scrollable_area->ScrollBy(ScrollOffset(0, 1000), kProgrammaticScroll);
+ scrollable_area->ScrollBy(ScrollOffset(0, 1000),
+ mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(scrollbar->CurrentPos(), scrollbar->Maximum());
}
@@ -1332,28 +1350,39 @@ TEST_P(PaintLayerScrollableAreaTest, ShowCustomResizerInTextarea) {
EXPECT_NE(paint_layer->GetScrollableArea()->Resizer(), nullptr);
}
-class PaintLayerScrollableAreaCompositingTest
- : public PaintLayerScrollableAreaTest {
- public:
- PaintLayerScrollableAreaCompositingTest() {
- if (GetParam() & kDoNotCompositeTrivial3D) {
- scoped_feature_list_.InitAndEnableFeature(
- blink::features::kDoNotCompositeTrivial3D);
- } else {
- scoped_feature_list_.InitAndDisableFeature(
- blink::features::kDoNotCompositeTrivial3D);
- }
- }
+TEST_P(PaintLayerScrollableAreaTest,
+ ApplyPendingHistoryRestoreScrollOffsetTwice) {
+ GetPage().GetSettings().SetTextAreasAreResizable(true);
+ SetBodyInnerHTML(R"HTML(
+ <!doctype HTML>
+ <div id="target" style="overflow: scroll; width: 50px; height: 50px">
+ <div style="width: 50px; height: 500px">
+ </div>
+ </div>
+ )HTML");
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
+ const auto* paint_layer =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))->Layer();
+
+ auto* scrollable_area = paint_layer->GetScrollableArea();
+
+ HistoryItem::ViewState view_state;
+ view_state.scroll_offset_ = ScrollOffset(0, 100);
+ scrollable_area->SetPendingHistoryRestoreScrollOffset(view_state, true);
+ scrollable_area->ApplyPendingHistoryRestoreScrollOffset();
+ EXPECT_EQ(ScrollOffset(0, 100), scrollable_area->GetScrollOffset());
-INSTANTIATE_DO_NOT_COMPOSITE_TRIVIAL_3D_P(
- PaintLayerScrollableAreaCompositingTest);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 50),
+ mojom::blink::ScrollType::kUser);
+
+ // The second call to ApplyPendingHistoryRestoreScrollOffset should
+ // do nothing, since the history was already restored.
+ scrollable_area->ApplyPendingHistoryRestoreScrollOffset();
+ EXPECT_EQ(ScrollOffset(0, 50), scrollable_area->GetScrollOffset());
+}
// Test that a trivial 3D transform results in composited scrolling.
-TEST_P(PaintLayerScrollableAreaCompositingTest, CompositeWithTrivial3D) {
+TEST_P(PaintLayerScrollableAreaTest, CompositeWithTrivial3D) {
SetBodyInnerHTML(R"HTML(
<style>
#scroller {
@@ -1375,4 +1404,156 @@ TEST_P(PaintLayerScrollableAreaCompositingTest, CompositeWithTrivial3D) {
EXPECT_TRUE(UsesCompositedScrolling(GetLayoutObjectByElementId("scroller")));
}
+class PaintLayerScrollableAreaTestLowEndPlatform
+ : public TestingPlatformSupport {
+ public:
+ bool IsLowEndDevice() override { return true; }
+};
+
+// Test that a trivial 3D transform results in composited scrolling even on
+// low-end devices that may not composite trivial 3D transforms.
+TEST_P(PaintLayerScrollableAreaTest, LowEndCompositeWithTrivial3D) {
+ ScopedTestingPlatformSupport<PaintLayerScrollableAreaTestLowEndPlatform>
+ platform;
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #scroller {
+ width: 100px;
+ height: 100px;
+ overflow: scroll;
+ transform: translateZ(0);
+ }
+ #scrolled {
+ width: 200px;
+ height: 200px;
+ }
+ </style>
+ <div id="scroller">
+ <div id="scrolled"></div>
+ </div>
+ )HTML");
+
+ EXPECT_TRUE(UsesCompositedScrolling(GetLayoutObjectByElementId("scroller")));
+}
+
+TEST_P(PaintLayerScrollableAreaTest, SetSnapContainerDataNeedsUpdate) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .scroller {
+ overflow: scroll;
+ height: 200px;
+ width: 200px;
+ }
+ </style>
+ <div id='first_scroller' class='scroller'>
+ <div style='height: 2000px;'></div>
+ </div>
+ <div id='second_scroller' class='scroller'>
+ <div style='height: 2000px;'></div>
+ </div>
+ )HTML");
+
+ auto* first_scroller = GetLayoutObjectByElementId("first_scroller");
+ auto* first_scrollable_area =
+ ToLayoutBoxModelObject(first_scroller)->GetScrollableArea();
+
+ auto* second_scroller = GetLayoutObjectByElementId("second_scroller");
+ auto* second_scrollable_area =
+ ToLayoutBoxModelObject(second_scroller)->GetScrollableArea();
+
+ EXPECT_EQ(&first_scroller->GetDocument().GetSnapCoordinator(),
+ &second_scroller->GetDocument().GetSnapCoordinator());
+
+ auto& snap_coordinator = first_scroller->GetDocument().GetSnapCoordinator();
+ EXPECT_FALSE(snap_coordinator.AnySnapContainerDataNeedsUpdate());
+
+ // SnapCoordinator needs to update all its snap containers if one of them asks
+ // for an update.
+ first_scrollable_area->SetSnapContainerDataNeedsUpdate(true);
+ EXPECT_TRUE(snap_coordinator.AnySnapContainerDataNeedsUpdate());
+
+ // SnapCoordinator still needs to update all its snap containers even if one
+ // of them asks not to.
+ second_scrollable_area->SetSnapContainerDataNeedsUpdate(false);
+ EXPECT_TRUE(snap_coordinator.AnySnapContainerDataNeedsUpdate());
+
+ first_scrollable_area->SetSnapContainerDataNeedsUpdate(false);
+ EXPECT_TRUE(snap_coordinator.AnySnapContainerDataNeedsUpdate());
+
+ snap_coordinator.UpdateAllSnapContainerDataIfNeeded();
+ EXPECT_FALSE(snap_coordinator.AnySnapContainerDataNeedsUpdate());
+}
+
+class ScrollTimelineForTest : public ScrollTimeline {
+ public:
+ ScrollTimelineForTest(
+ Document* document,
+ Element* scroll_source,
+ CSSPrimitiveValue* start_scroll_offset =
+ CSSNumericLiteralValue::Create(10.0,
+ CSSPrimitiveValue::UnitType::kPixels),
+ CSSPrimitiveValue* end_scroll_offset =
+ CSSNumericLiteralValue::Create(90.0,
+ CSSPrimitiveValue::UnitType::kPixels))
+ : ScrollTimeline(document,
+ scroll_source,
+ ScrollTimeline::Vertical,
+ start_scroll_offset,
+ end_scroll_offset,
+ 100.0),
+ invalidated_(false) {}
+ void Invalidate() override {
+ ScrollTimeline::Invalidate();
+ invalidated_ = true;
+ }
+ bool Invalidated() const { return invalidated_; }
+ void ResetInvalidated() { invalidated_ = false; }
+ void Trace(Visitor* visitor) override { ScrollTimeline::Trace(visitor); }
+
+ private:
+ bool invalidated_;
+};
+
+// Verify that scrollable area changes invalidate scroll timeline.
+TEST_P(PaintLayerScrollableAreaTest, ScrollTimelineInvalidation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #scroller { overflow: scroll; width: 100px; height: 100px; }
+ #spacer { height: 1000px; }
+ </style>
+ <div id='scroller'>
+ <div id ='spacer'></div>
+ </div>
+ )HTML");
+
+ LayoutBoxModelObject* scroller =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
+ PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 20),
+ mojom::blink::ScrollType::kProgrammatic);
+ Element* scroller_element = GetElementById("scroller");
+ ScrollTimelineForTest* scroll_timeline =
+ MakeGarbageCollected<ScrollTimelineForTest>(&GetDocument(),
+ scroller_element);
+ scroll_timeline->ResetInvalidated();
+ // Verify that changing scroll offset invalidates scroll timeline.
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 30),
+ mojom::blink::ScrollType::kProgrammatic);
+ EXPECT_TRUE(scroll_timeline->Invalidated());
+ scroll_timeline->ResetInvalidated();
+
+ // Verify that changing scroller size invalidates scroll timeline.
+ scroller_element->setAttribute(html_names::kStyleAttr, "height:110px;");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(scroll_timeline->Invalidated());
+ scroll_timeline->ResetInvalidated();
+
+ // Verify that changing content area size invalidates scroll timeline.
+ Element* spacer_element = GetElementById("spacer");
+ spacer_element->setAttribute(html_names::kStyleAttr, "height:900px;");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_TRUE(scroll_timeline->Invalidated());
+ scroll_timeline->ResetInvalidated();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
index 4e1c981916e..e660390d496 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_stacking_node.cc
@@ -109,21 +109,47 @@ static bool ZIndexLessThan(const PaintLayer* first, const PaintLayer* second) {
second->GetLayoutObject().StyleRef().ZIndex();
}
-static void SetIfHigher(const PaintLayer*& first, const PaintLayer* second) {
+static bool SetIfHigher(const PaintLayer*& first, const PaintLayer* second) {
if (!second)
- return;
+ return false;
DCHECK_GE(second->GetLayoutObject().StyleRef().ZIndex(), 0);
// |second| appears later in the tree, so it's higher than |first| if its
// z-index >= |first|'s z-index.
- if (!first || !ZIndexLessThan(second, first))
+ if (!first || !ZIndexLessThan(second, first)) {
first = second;
+ return true;
+ }
+ return false;
}
-// For finding the proper z-order of reparented overlay scrollbars.
+// For finding the proper z-order of reparented overlay overflow controls.
struct PaintLayerStackingNode::HighestLayers {
- const PaintLayer* highest_absolute_position = nullptr;
- const PaintLayer* highest_fixed_position = nullptr;
- const PaintLayer* highest_in_flow_stacked = nullptr;
+ enum LayerType {
+ kAbsolutePosition,
+ kFixedPosition,
+ kInFlowStacked,
+ kLayerTypeCount
+ };
+ std::array<const PaintLayer*, kLayerTypeCount> highest_layers = {
+ nullptr, nullptr, nullptr};
+ Vector<LayerType, kLayerTypeCount> highest_layers_order;
+
+ void UpdateOrderForSubtreeHighestLayers(LayerType type,
+ const PaintLayer* layer) {
+ if (SetIfHigher(highest_layers[type], layer)) {
+ auto* new_end = std::remove(highest_layers_order.begin(),
+ highest_layers_order.end(), type);
+ if (new_end != highest_layers_order.end()) {
+ // |highest_layers_order| doesn't have duplicate elements, std::remove
+ // will find at most one element at a time. So we don't shrink it and
+ // just update the value of the |new_end|.
+ DCHECK(new_end + 1 == highest_layers_order.end());
+ *new_end = type;
+ } else {
+ highest_layers_order.push_back(type);
+ }
+ }
+ }
void Update(const PaintLayer& layer) {
const auto& style = layer.GetLayoutObject().StyleRef();
@@ -136,17 +162,18 @@ struct PaintLayerStackingNode::HighestLayers {
return;
if (style.GetPosition() == EPosition::kAbsolute)
- SetIfHigher(highest_absolute_position, &layer);
+ UpdateOrderForSubtreeHighestLayers(kAbsolutePosition, &layer);
else if (style.GetPosition() == EPosition::kFixed)
- SetIfHigher(highest_fixed_position, &layer);
+ UpdateOrderForSubtreeHighestLayers(kFixedPosition, &layer);
else
- SetIfHigher(highest_in_flow_stacked, &layer);
+ UpdateOrderForSubtreeHighestLayers(kInFlowStacked, &layer);
}
void Merge(HighestLayers& child) {
- SetIfHigher(highest_absolute_position, child.highest_absolute_position);
- SetIfHigher(highest_fixed_position, child.highest_fixed_position);
- SetIfHigher(highest_in_flow_stacked, child.highest_in_flow_stacked);
+ for (auto layer_type : child.highest_layers_order) {
+ UpdateOrderForSubtreeHighestLayers(layer_type,
+ child.highest_layers[layer_type]);
+ }
}
};
@@ -231,16 +258,18 @@ void PaintLayerStackingNode::CollectLayers(PaintLayer& paint_layer,
}
if (has_overlay_overflow_controls) {
- const PaintLayer* layer_to_paint_overlay_overflow_controls_after =
- subtree_highest_layers->highest_in_flow_stacked;
- if (object.CanContainFixedPositionObjects()) {
+ const PaintLayer* layer_to_paint_overlay_overflow_controls_after = nullptr;
+ for (auto layer_type : subtree_highest_layers->highest_layers_order) {
+ if (layer_type == HighestLayers::kFixedPosition &&
+ !object.CanContainFixedPositionObjects())
+ continue;
+ if (layer_type == HighestLayers::kAbsolutePosition &&
+ !object.CanContainAbsolutePositionObjects())
+ continue;
SetIfHigher(layer_to_paint_overlay_overflow_controls_after,
- subtree_highest_layers->highest_fixed_position);
- }
- if (object.CanContainAbsolutePositionObjects()) {
- SetIfHigher(layer_to_paint_overlay_overflow_controls_after,
- subtree_highest_layers->highest_absolute_position);
+ subtree_highest_layers->highest_layers[layer_type]);
}
+
if (layer_to_paint_overlay_overflow_controls_after) {
layer_to_overlay_overflow_controls_painting_after_
.insert(layer_to_paint_overlay_overflow_controls_after, PaintLayers())
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
index 247a10f525d..f0dc94a3304 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -206,9 +206,10 @@ TEST_P(PaintLayerTest, CompositedScrollingNoNeedsRepaint) {
EXPECT_EQ(kNotComposited, content_layer->GetCompositingState());
EXPECT_EQ(PhysicalOffset(), content_layer->LocationWithoutPositionOffset());
- scroll_layer->GetScrollableArea()->SetScrollOffset(ScrollOffset(1000, 1000),
- kProgrammaticScroll);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ scroll_layer->GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(1000, 1000), mojom::blink::ScrollType::kProgrammatic);
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_EQ(PhysicalOffset(0, 0),
content_layer->LocationWithoutPositionOffset());
EXPECT_EQ(
@@ -240,9 +241,10 @@ TEST_P(PaintLayerTest, NonCompositedScrollingNeedsRepaint) {
EXPECT_EQ(kNotComposited, scroll_layer->GetCompositingState());
EXPECT_EQ(PhysicalOffset(), content_layer->LocationWithoutPositionOffset());
- scroll_layer->GetScrollableArea()->SetScrollOffset(ScrollOffset(1000, 1000),
- kProgrammaticScroll);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ scroll_layer->GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(1000, 1000), mojom::blink::ScrollType::kProgrammatic);
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_EQ(PhysicalOffset(0, 0),
content_layer->LocationWithoutPositionOffset());
EXPECT_EQ(
@@ -972,7 +974,41 @@ TEST_P(ReorderOverlayOverflowControlsTest,
EXPECT_FALSE(LayersPaintingOverlayOverflowControlsAfter(child));
}
-TEST_P(PaintLayerTest, SubsequenceCachingStackingContexts) {
+TEST_P(ReorderOverlayOverflowControlsTest,
+ AdjustAccessingOrderForSubtreeHighestLayers) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ div {
+ width: 200px;
+ height: 200px;
+ }
+ div > div {
+ height: 300px;
+ }
+ #ancestor, #child_2 {
+ position: relative;
+ }
+ #child_1 {
+ position: absolute;
+ }
+ </style>
+ <div id='ancestor'>
+ <div id='child_1'></div>
+ <div id='child_2'>
+ <div id='descendant'></div>
+ </div>
+ </div>
+ )HTML");
+
+ InitOverflowStyle("ancestor");
+
+ auto* ancestor = GetPaintLayerByElementId("ancestor");
+ auto* child = GetPaintLayerByElementId("child_2");
+ EXPECT_TRUE(ancestor->NeedsReorderOverlayOverflowControls());
+ EXPECT_TRUE(LayersPaintingOverlayOverflowControlsAfter(child));
+}
+
+TEST_P(PaintLayerTest, SubsequenceCachingStackedLayers) {
SetBodyInnerHTML(R"HTML(
<div id='parent' style='position:relative'>
<div id='child1' style='position: relative'>
@@ -1242,8 +1278,8 @@ TEST_P(PaintLayerTest, PaintInvalidationOnNonCompositedScroll) {
content_layer->FirstFragment().VisualRect());
EXPECT_EQ(IntRect(0, 30, 50, 5), content->FirstFragment().VisualRect());
- scroller->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 20),
- kProgrammaticScroll);
+ scroller->GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(0, 20), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(0, 30, 50, 10),
content_layer->FirstFragment().VisualRect());
@@ -1271,8 +1307,8 @@ TEST_P(PaintLayerTest, PaintInvalidationOnCompositedScroll) {
content_layer->FirstFragment().VisualRect());
EXPECT_EQ(IntRect(0, 30, 50, 5), content->FirstFragment().VisualRect());
- scroller->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 20),
- kProgrammaticScroll);
+ scroller->GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(0, 20), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(IntRect(0, 30, 50, 10),
content_layer->FirstFragment().VisualRect());
@@ -1602,8 +1638,8 @@ TEST_P(PaintLayerTest, FloatLayerUnderInlineLayerScrolled) {
PaintLayer* floating = GetPaintLayerByElementId("floating");
PaintLayer* span = GetPaintLayerByElementId("span");
PaintLayer* container = GetPaintLayerByElementId("container");
- container->GetScrollableArea()->SetScrollOffset(ScrollOffset(0, 400),
- kProgrammaticScroll);
+ container->GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(0, 400), mojom::blink::ScrollType::kProgrammatic);
EXPECT_EQ(span, floating->Parent());
if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
@@ -1883,8 +1919,8 @@ TEST_P(PaintLayerTest, ColumnSpanLayerUnderExtraLayerScrolled) {
PaintLayer* spanner = GetPaintLayerByElementId("spanner");
PaintLayer* extra_layer = GetPaintLayerByElementId("extraLayer");
PaintLayer* columns = GetPaintLayerByElementId("columns");
- columns->GetScrollableArea()->SetScrollOffset(ScrollOffset(200, 0),
- kProgrammaticScroll);
+ columns->GetScrollableArea()->SetScrollOffset(
+ ScrollOffset(200, 0), mojom::blink::ScrollType::kProgrammatic);
EXPECT_EQ(extra_layer, spanner->Parent());
EXPECT_EQ(columns, spanner->ContainingLayer());
@@ -1952,7 +1988,8 @@ TEST_P(PaintLayerTest, NeedsRepaintOnSelfPaintingStatusChange) {
target_element->setAttribute(html_names::kStyleAttr,
"overflow: hidden; float: left");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// TODO(yosin): Once multicol in LayoutNG, we should remove following
// assignments. This is because the layout tree maybe reattached. In LayoutNG
// phase 1, layout tree is reattached because multicol forces legacy layout.
@@ -1989,7 +2026,8 @@ TEST_P(PaintLayerTest, NeedsRepaintOnRemovingStackedLayer) {
body->setAttribute(html_names::kStyleAttr, "margin-top: 0");
target_element->setAttribute(html_names::kStyleAttr, "top: 0");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(target_object->HasLayer());
EXPECT_TRUE(body_layer->SelfNeedsRepaint());
@@ -2087,8 +2125,8 @@ TEST_P(PaintLayerTest, SquashingOffsets) {
EXPECT_EQ(PhysicalOffset(), squashed->ComputeOffsetFromAncestor(
squashed->TransformAncestorOrRoot()));
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 25),
- kUserScroll);
+ GetDocument().View()->LayoutViewport()->ScrollBy(
+ ScrollOffset(0, 25), mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
PaintLayer::MapPointInPaintInvalidationContainerToBacking(
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_phase.h b/chromium/third_party/blink/renderer/core/paint/paint_phase.h
index 039da1239f3..579ecf8f9a3 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_phase.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_phase.h
@@ -93,7 +93,7 @@ enum class PaintPhase {
// The below are auxiliary phases which are used to paint special effects.
kOverlayOverflowControls,
- kSelection,
+ kSelectionDragImage,
kTextClip,
kMask,
@@ -128,7 +128,7 @@ enum GlobalPaintFlag {
// Used when painting selection as part of a drag-image. This
// flag disables a lot of the painting code and specifically
// triggers a PaintPhaseSelection.
- kGlobalPaintSelectionOnly = 1 << 0,
+ kGlobalPaintSelectionDragImageOnly = 1 << 0,
// Used when painting a drag-image or printing in order to
// ignore the hardware layers and paint the whole tree
// into the topmost layer.
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 6e0a4994f2e..6810fb3e4f7 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -20,7 +20,11 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_table_row.h"
#include "third_party/blink/renderer/core/layout/layout_table_section.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h"
@@ -135,13 +139,17 @@ void PaintPropertyTreeBuilder::SetupContextForFrame(
namespace {
class FragmentPaintPropertyTreeBuilder {
+ STACK_ALLOCATED();
+
public:
FragmentPaintPropertyTreeBuilder(
const LayoutObject& object,
+ NGPrePaintInfo* pre_paint_info,
PaintPropertyTreeBuilderContext& full_context,
PaintPropertyTreeBuilderFragmentContext& context,
FragmentData& fragment_data)
: object_(object),
+ pre_paint_info_(pre_paint_info),
full_context_(full_context),
context_(context),
fragment_data_(fragment_data),
@@ -187,7 +195,7 @@ class FragmentPaintPropertyTreeBuilder {
ALWAYS_INLINE void UpdateClipPathCache();
ALWAYS_INLINE void UpdateStickyTranslation();
ALWAYS_INLINE void UpdateTransform();
- ALWAYS_INLINE void UpdateTransformForNonRootSVG();
+ ALWAYS_INLINE void UpdateTransformForSVGChild();
ALWAYS_INLINE bool EffectCanUseCurrentClipAsOutputClip() const;
ALWAYS_INLINE void UpdateEffect();
ALWAYS_INLINE void UpdateFilter();
@@ -213,6 +221,8 @@ class FragmentPaintPropertyTreeBuilder {
full_context_.force_subtree_update_reasons;
}
+ bool IsInNGFragmentTraversal() const { return pre_paint_info_; }
+
void OnUpdate(PaintPropertyChangeType change) {
property_changed_ = std::max(property_changed_, change);
}
@@ -251,6 +261,7 @@ class FragmentPaintPropertyTreeBuilder {
}
const LayoutObject& object_;
+ NGPrePaintInfo* pre_paint_info_;
// The tree builder context for the whole object.
PaintPropertyTreeBuilderContext& full_context_;
// The tree builder context for the current fragment, which is one of the
@@ -262,17 +273,6 @@ class FragmentPaintPropertyTreeBuilder {
PaintPropertyChangeType::kUnchanged;
};
-static bool NeedsScrollNode(const LayoutObject& object,
- CompositingReasons direct_compositing_reasons) {
- if (!object.HasOverflowClip())
- return false;
-
- if (direct_compositing_reasons & CompositingReason::kRootScroller)
- return true;
-
- return ToLayoutBox(object).GetScrollableArea()->ScrollsOverflow();
-}
-
// True if a scroll translation is needed for static scroll offset (e.g.,
// overflow hidden with scroll), or if a scroll node is needed for composited
// scrolling.
@@ -288,7 +288,7 @@ static bool NeedsScrollOrScrollTranslation(
ScrollOffset scroll_offset = box.GetScrollableArea()->GetScrollOffset();
return !scroll_offset.IsZero() ||
- NeedsScrollNode(object, direct_compositing_reasons);
+ box.NeedsScrollNode(direct_compositing_reasons);
}
static bool NeedsReplacedContentTransform(const LayoutObject& object) {
@@ -350,7 +350,7 @@ static bool NeedsIsolationNodes(const LayoutObject& object) {
// Layout view establishes isolation with the exception of local roots (since
// they are already essentially isolated).
- if (object.IsLayoutView()) {
+ if (IsA<LayoutView>(object)) {
const auto* parent_frame = object.GetFrame()->Tree().Parent();
return IsA<LocalFrame>(parent_frame);
}
@@ -382,7 +382,7 @@ static bool NeedsPaintOffsetTranslation(
const LayoutBoxModelObject& box_model = ToLayoutBoxModelObject(object);
- if (box_model.IsLayoutView()) {
+ if (IsA<LayoutView>(box_model)) {
// A translation node for LayoutView is always created to ensure fixed and
// absolute contexts use the correct transform space.
return true;
@@ -421,6 +421,12 @@ static bool NeedsPaintOffsetTranslation(
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
if (direct_compositing_reasons != CompositingReason::kNone)
return true;
+ // In CompositeAfterPaint though we don't treat hidden backface as
+ // a direct compositing reason, it's very likely that the object will
+ // be composited, so a paint offset translation will be beneficial.
+ if (box_model.StyleRef().BackfaceVisibility() ==
+ EBackfaceVisibility::kHidden)
+ return true;
} else if (box_model.GetCompositingState() == kPaintsIntoOwnBacking) {
return true;
}
@@ -481,7 +487,7 @@ bool FragmentPaintPropertyTreeBuilder::IsAffectedByOuterViewportBoundsDelta()
// It's affected by viewport only if the container is the LayoutView.
DCHECK_EQ(full_context_.container_for_fixed_position, object_.Container());
- return full_context_.container_for_fixed_position->IsLayoutView();
+ return IsA<LayoutView>(full_context_.container_for_fixed_position);
}
void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
@@ -502,12 +508,12 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
IsAffectedByOuterViewportBoundsDelta();
state.direct_compositing_reasons =
full_context_.direct_compositing_reasons &
- CompositingReason::kScrollDependentPosition;
+ CompositingReason::kDirectReasonsForPaintOffsetTranslationProperty;
state.rendering_context_id = context_.current.rendering_context_id;
OnUpdate(properties_->UpdatePaintOffsetTranslation(
*context_.current.transform, std::move(state)));
context_.current.transform = properties_->PaintOffsetTranslation();
- if (object_.IsLayoutView()) {
+ if (IsA<LayoutView>(object_)) {
context_.absolute_position.transform =
properties_->PaintOffsetTranslation();
context_.fixed_position.transform = properties_->PaintOffsetTranslation();
@@ -548,8 +554,20 @@ void FragmentPaintPropertyTreeBuilder::UpdateStickyTranslation() {
// DCHECK_EQ(scroller_properties->Scroll(), context_.current.scroll);
// However there is a bug that AncestorOverflowLayer() may be computed
// incorrectly with clip escaping involved.
- if (scroller_properties &&
- scroller_properties->Scroll() == context_.current.scroll) {
+ bool nearest_scroller_is_clip =
+ scroller_properties &&
+ scroller_properties->Scroll() == context_.current.scroll;
+
+ // Additionally, we also want to make sure that the nearest scroller
+ // actually translates this node. If it doesn't (e.g. a position fixed
+ // node in a scrolling document), there's no point in adding a constraint
+ // since scrolling won't affect it. Indeed, if we do add it, the
+ // compositor assumes scrolling does affect it and produces incorrect
+ // results.
+ bool translates_with_nearest_scroller =
+ context_.current.transform->NearestScrollTranslationNode()
+ .ScrollNode() == context_.current.scroll;
+ if (nearest_scroller_is_clip && translates_with_nearest_scroller) {
const StickyPositionScrollingConstraints& layout_constraint =
layer->AncestorOverflowLayer()
->GetScrollableArea()
@@ -560,19 +578,17 @@ void FragmentPaintPropertyTreeBuilder::UpdateStickyTranslation() {
constraint->is_anchored_right = layout_constraint.is_anchored_right;
constraint->is_anchored_top = layout_constraint.is_anchored_top;
constraint->is_anchored_bottom = layout_constraint.is_anchored_bottom;
+
constraint->left_offset = layout_constraint.left_offset.ToFloat();
constraint->right_offset = layout_constraint.right_offset.ToFloat();
constraint->top_offset = layout_constraint.top_offset.ToFloat();
constraint->bottom_offset = layout_constraint.bottom_offset.ToFloat();
constraint->constraint_box_rect =
- PixelSnappedIntRect(box_model.ComputeStickyConstrainingRect());
- constraint->scroll_container_relative_sticky_box_rect =
- PixelSnappedIntRect(
- layout_constraint.scroll_container_relative_sticky_box_rect);
- constraint->scroll_container_relative_containing_block_rect =
- PixelSnappedIntRect(
- layout_constraint
- .scroll_container_relative_containing_block_rect);
+ FloatRect(box_model.ComputeStickyConstrainingRect());
+ constraint->scroll_container_relative_sticky_box_rect = FloatRect(
+ layout_constraint.scroll_container_relative_sticky_box_rect);
+ constraint->scroll_container_relative_containing_block_rect = FloatRect(
+ layout_constraint.scroll_container_relative_containing_block_rect);
if (PaintLayer* sticky_box_shifting_ancestor =
layout_constraint.nearest_sticky_layer_shifting_sticky_box) {
constraint->nearest_element_shifting_sticky_box =
@@ -603,18 +619,29 @@ void FragmentPaintPropertyTreeBuilder::UpdateStickyTranslation() {
context_.current.transform = properties_->StickyTranslation();
}
-static bool NeedsTransformForNonRootSVG(const LayoutObject& object) {
+static bool NeedsTransformForSVGChild(const LayoutObject& object) {
// TODO(pdr): Check for the presence of a transform instead of the value.
// Checking for an identity matrix will cause the property tree structure
// to change during animations if the animation passes through the
// identity matrix.
+ // TODO(crbug.com/666244): Check CompositingReasonsForAnimation here when we
+ // support composited transform animations in SVG.
return object.IsSVGChild() && !object.IsText() &&
!object.LocalToSVGParentTransform().IsIdentity();
}
+static void SetTransformNodeStateFromAffineTransform(
+ TransformPaintPropertyNode::State& state,
+ const AffineTransform& transform) {
+ if (transform.IsIdentityOrTranslation())
+ state.transform_and_origin = {FloatSize(transform.E(), transform.F())};
+ else
+ state.transform_and_origin = {TransformationMatrix(transform)};
+}
+
// SVG does not use the general transform update of |UpdateTransform|, instead
// creating a transform node for SVG-specific transforms without 3D.
-void FragmentPaintPropertyTreeBuilder::UpdateTransformForNonRootSVG() {
+void FragmentPaintPropertyTreeBuilder::UpdateTransformForSVGChild() {
DCHECK(properties_);
DCHECK(object_.IsSVGChild());
// SVG does not use paint offset internally, except for SVGForeignObject which
@@ -624,9 +651,12 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransformForNonRootSVG() {
if (NeedsPaintPropertyUpdate()) {
AffineTransform transform = object_.LocalToSVGParentTransform();
- if (NeedsTransformForNonRootSVG(object_)) {
+ if (NeedsTransformForSVGChild(object_)) {
// The origin is included in the local transform, so leave origin empty.
- TransformPaintPropertyNode::State state{TransformationMatrix(transform)};
+ // TODO(crbug.com/666244): Support composited transform animation for SVG
+ // using similar code as |UpdateTransform| for animations.
+ TransformPaintPropertyNode::State state;
+ SetTransformNodeStateFromAffineTransform(state, transform);
OnUpdate(properties_->UpdateTransform(*context_.current.transform,
std::move(state)));
} else {
@@ -666,8 +696,7 @@ static CompositingReasons CompositingReasonsForTransformProperty() {
// will-change:opacity to avoid raster invalidation (caused by otherwise a
// created/deleted effect node) when we start/stop an opacity animation.
// https://crbug.com/942681
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- reasons |= CompositingReason::kWillChangeOpacity;
+ reasons |= CompositingReason::kWillChangeOpacity;
return reasons;
}
@@ -707,7 +736,7 @@ static bool ActiveTransformAnimationIsAxisAligned(
void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
if (object_.IsSVGChild()) {
- UpdateTransformForNonRootSVG();
+ UpdateTransformForSVGChild();
return;
}
@@ -738,10 +767,12 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
bool disable_2d_translation_optimization =
full_context_.direct_compositing_reasons &
CompositingReason::kActiveTransformAnimation;
- state.transform_and_origin =
- TransformPaintPropertyNode::TransformAndOrigin(
- matrix, TransformOrigin(box),
- disable_2d_translation_optimization);
+ if (!disable_2d_translation_optimization &&
+ matrix.IsIdentityOr2DTranslation()) {
+ state.transform_and_origin = {matrix.To2DTranslation()};
+ } else {
+ state.transform_and_origin = {matrix, TransformOrigin(box)};
+ }
// TODO(trchen): transform-style should only be respected if a
// PaintLayer is created. If a node with transform-style: preserve-3d
@@ -778,9 +809,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
style.IsRunningTransformAnimationOnCompositor();
auto effective_change_type = properties_->UpdateTransform(
*context_.current.transform, std::move(state), animation_state);
- // TODO(crbug.com/953322): We need to fix this to work with CAP as well.
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- effective_change_type ==
+ if (effective_change_type ==
PaintPropertyChangeType::kChangedOnlySimpleValues &&
properties_->Transform()->HasDirectCompositingReasons()) {
if (auto* paint_artifact_compositor =
@@ -826,8 +855,9 @@ static bool NeedsClipPathClip(const LayoutObject& object) {
return false;
}
-// TODO(crbug.com/900241): Remove this function and let the caller use
-// CompositingReason::kDirectReasonForEffectProperty directly.
+// TODO(crbug.com/900241): When this bug is fixed, we should let NeedsEffect()
+// use CompositingReason::kDirectReasonForEffectProperty directly instead of
+// calling this function. We should still call this function in UpdateEffect().
static CompositingReasons CompositingReasonsForEffectProperty() {
CompositingReasons reasons =
CompositingReason::kDirectReasonsForEffectProperty;
@@ -839,8 +869,9 @@ static CompositingReasons CompositingReasonsForEffectProperty() {
// will-change:transform to avoid raster invalidation (caused by otherwise a
// created/deleted effect node) when we start/stop a transform animation.
// https://crbug.com/942681
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- reasons |= CompositingReason::kWillChangeTransform;
+ // In CompositeAfterPaint, this also avoids decomposition of the effect when
+ // the object is forced compositing with will-change:transform.
+ reasons |= CompositingReason::kWillChangeTransform;
return reasons;
}
@@ -1005,8 +1036,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
OnUpdateClip(properties_->UpdateMaskClip(
*context_.current.clip,
- ClipPaintPropertyNode::State{context_.current.transform,
- FloatRoundedRect(combined_clip)}));
+ ClipPaintPropertyNode::State(context_.current.transform,
+ FloatRoundedRect(combined_clip))));
output_clip = properties_->MaskClip();
} else {
OnClearClip(properties_->ClearMaskClip());
@@ -1079,9 +1110,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
// If we have simple value change, which means opacity, we should try to
// directly update it on the PaintArtifactCompositor in order to avoid
// doing a full rebuild.
- // TODO(crbug.com/953322): We need to fix this to work with CAP as well.
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
- effective_change_type ==
+ if (effective_change_type ==
PaintPropertyChangeType::kChangedOnlySimpleValues &&
properties_->Effect()->HasDirectCompositingReasons()) {
if (auto* paint_artifact_compositor =
@@ -1150,8 +1179,9 @@ static bool NeedsLinkHighlightEffect(const LayoutObject& object) {
return page->GetLinkHighlight().NeedsHighlightEffect(object);
}
-// TODO(crbug.com/900241): Remove this function and let the caller use
-// CompositingReason::kDirectReasonForFilterProperty directly.
+// TODO(crbug.com/900241): When this bug is fixed, we should let NeedsFilter()
+// use CompositingReason::kDirectReasonForFilterProperty directly instead of
+// calling this function. We should still call this function in UpdateFilter().
static CompositingReasons CompositingReasonsForFilterProperty() {
CompositingReasons reasons =
CompositingReason::kDirectReasonsForFilterProperty;
@@ -1163,10 +1193,10 @@ static CompositingReasons CompositingReasonsForFilterProperty() {
// created for will-change:transform/opacity to avoid raster invalidation
// (caused by otherwise a created/deleted filter node) when we start/stop a
// transform/opacity animation. https://crbug.com/942681
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- reasons |= CompositingReason::kWillChangeTransform |
- CompositingReason::kWillChangeOpacity;
- }
+ // In CompositeAfterPaint, this also avoids decomposition of the filter when
+ // the object is forced compositing with will-change:transform/opacity.
+ reasons |= CompositingReason::kWillChangeTransform |
+ CompositingReason::kWillChangeOpacity;
return reasons;
}
@@ -1220,7 +1250,9 @@ void FragmentPaintPropertyTreeBuilder::UpdateFilter() {
// On the other hand, "B" should not be clipped because the overflow clip
// is not in its containing block chain, but as the filter output will be
// clipped, so a blurred "B" may still be invisible.
- if (!state.filter.IsEmpty())
+ if (!state.filter.IsEmpty() ||
+ (full_context_.direct_compositing_reasons &
+ CompositingReason::kActiveFilterAnimation))
state.output_clip = context_.current.clip;
// TODO(trchen): A filter may contain spatial operations such that an
@@ -1271,10 +1303,12 @@ void FragmentPaintPropertyTreeBuilder::UpdateFragmentClip() {
if (NeedsPaintPropertyUpdate()) {
if (context_.fragment_clip) {
- const auto& clip_rect = ToSnappedClipRect(*context_.fragment_clip);
+ const auto& clip_rect = *context_.fragment_clip;
OnUpdateClip(properties_->UpdateFragmentClip(
*context_.current.clip,
- ClipPaintPropertyNode::State{context_.current.transform, clip_rect}));
+ ClipPaintPropertyNode::State(context_.current.transform,
+ FloatRoundedRect(FloatRect(clip_rect)),
+ ToSnappedClipRect(clip_rect))));
} else {
OnClearClip(properties_->ClearFragmentClip());
}
@@ -1302,11 +1336,13 @@ void FragmentPaintPropertyTreeBuilder::UpdateCssClip() {
// object must be a container for absolute position descendants, and will
// copy from in-flow context later at updateOutOfFlowContext() step.
DCHECK(object_.CanContainAbsolutePositionObjects());
- const auto& clip_rect = ToSnappedClipRect(
- ToLayoutBox(object_).ClipRect(context_.current.paint_offset));
+ const auto& clip_rect =
+ ToLayoutBox(object_).ClipRect(context_.current.paint_offset);
OnUpdateClip(properties_->UpdateCssClip(
*context_.current.clip,
- ClipPaintPropertyNode::State{context_.current.transform, clip_rect}));
+ ClipPaintPropertyNode::State(context_.current.transform,
+ FloatRoundedRect(FloatRect(clip_rect)),
+ ToSnappedClipRect(clip_rect))));
} else {
OnClearClip(properties_->ClearCssClip());
}
@@ -1331,9 +1367,9 @@ void FragmentPaintPropertyTreeBuilder::UpdateClipPathClip(
if (!NeedsClipPathClip(object_)) {
OnClearClip(properties_->ClearClipPathClip());
} else {
- ClipPaintPropertyNode::State state;
- state.local_transform_space = context_.current.transform;
- state.clip_rect = FloatRoundedRect(*fragment_data_.ClipPathBoundingBox());
+ ClipPaintPropertyNode::State state(
+ context_.current.transform,
+ FloatRoundedRect(*fragment_data_.ClipPathBoundingBox()));
state.clip_path = fragment_data_.ClipPathPath();
OnUpdateClip(properties_->UpdateClipPathClip(*context_.current.clip,
std::move(state)));
@@ -1351,7 +1387,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateClipPathClip(
// issue artificial page clip for each page, and always print from the origin
// of the contents for which no scroll offset should be applied.
static bool IsPrintingRootLayoutView(const LayoutObject& object) {
- if (!object.IsLayoutView())
+ if (!IsA<LayoutView>(object))
return false;
const auto& frame = *object.GetFrame();
@@ -1441,9 +1477,8 @@ bool FragmentPaintPropertyTreeBuilder::NeedsOverflowControlsClip() const {
scroll_controls_bounds.Unite(scrollbar->FrameRect());
if (const auto* scrollbar = scrollable_area->VerticalScrollbar())
scroll_controls_bounds.Unite(scrollbar->FrameRect());
- auto pixel_snapped_border_box_rect =
- box.PixelSnappedBorderBoxRect(context_.current.paint_offset);
- pixel_snapped_border_box_rect.SetLocation(IntPoint());
+ IntRect pixel_snapped_border_box_rect(
+ IntPoint(), box.PixelSnappedBorderBoxSize(context_.current.paint_offset));
return !pixel_snapped_border_box_rect.Contains(scroll_controls_bounds);
}
@@ -1491,11 +1526,13 @@ void FragmentPaintPropertyTreeBuilder::UpdateOverflowControlsClip() {
if (NeedsOverflowControlsClip()) {
// Clip overflow controls to the border box rect. Not wrapped with
// OnUpdateClip() because this clip doesn't affect descendants.
- const auto& clip_rect = ToSnappedClipRect(PhysicalRect(
- context_.current.paint_offset, ToLayoutBox(object_).Size()));
+ const auto& clip_rect = PhysicalRect(context_.current.paint_offset,
+ ToLayoutBox(object_).Size());
properties_->UpdateOverflowControlsClip(
*context_.current.clip,
- ClipPaintPropertyNode::State{context_.current.transform, clip_rect});
+ ClipPaintPropertyNode::State(context_.current.transform,
+ FloatRoundedRect(FloatRect(clip_rect)),
+ ToSnappedClipRect(clip_rect)));
} else {
properties_->ClearOverflowControlsClip();
}
@@ -1512,10 +1549,12 @@ void FragmentPaintPropertyTreeBuilder::UpdateInnerBorderRadiusClip() {
if (NeedsPaintPropertyUpdate()) {
if (NeedsInnerBorderRadiusClip(object_)) {
const LayoutBox& box = ToLayoutBox(object_);
- ClipPaintPropertyNode::State state;
- state.local_transform_space = context_.current.transform;
- state.clip_rect = box.StyleRef().GetRoundedInnerBorderFor(LayoutRect(
- context_.current.paint_offset.ToLayoutPoint(), box.Size()));
+ LayoutRect box_rect(context_.current.paint_offset.ToLayoutPoint(),
+ box.Size());
+ ClipPaintPropertyNode::State state(
+ context_.current.transform,
+ box.StyleRef().GetInnerBorderFor(box_rect),
+ box.StyleRef().GetRoundedInnerBorderFor(box_rect));
OnUpdateClip(properties_->UpdateInnerBorderRadiusClip(
*context_.current.clip, std::move(state)));
} else {
@@ -1534,15 +1573,16 @@ static PhysicalRect OverflowClipRect(const LayoutBox& box,
// here instead of LayoutBox::OverflowClipRect because the layout size of the
// scrolling content is still affected by overlay scrollbar behavior, just not
// the clip.
- auto behavior = box.IsLayoutView() ? kIgnorePlatformAndCSSOverlayScrollbarSize
- : kIgnorePlatformOverlayScrollbarSize;
+ auto behavior = IsA<LayoutView>(box)
+ ? kIgnorePlatformAndCSSOverlayScrollbarSize
+ : kIgnorePlatformOverlayScrollbarSize;
return box.OverflowClipRect(offset, behavior);
}
static bool CanOmitOverflowClip(const LayoutObject& object) {
DCHECK(NeedsOverflowClip(object));
- if (object.IsLayoutView() && !object.GetFrame()->ClipsContent()) {
+ if (IsA<LayoutView>(object) && !object.GetFrame()->ClipsContent()) {
return true;
}
@@ -1589,8 +1629,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateOverflowClip() {
if (NeedsPaintPropertyUpdate()) {
if (NeedsOverflowClip(object_) && !CanOmitOverflowClip(object_)) {
- ClipPaintPropertyNode::State state;
- state.local_transform_space = context_.current.transform;
+ ClipPaintPropertyNode::State state(context_.current.transform,
+ FloatRoundedRect());
if (object_.IsLayoutReplaced()) {
const LayoutReplaced& replaced = ToLayoutReplaced(object_);
@@ -1600,39 +1640,46 @@ void FragmentPaintPropertyTreeBuilder::UpdateOverflowClip() {
// here, before applying padding and corner rounding.
PhysicalRect content_rect(context_.current.paint_offset,
replaced.Size());
- if (replaced.IsVideo()) {
+ if (IsA<LayoutVideo>(replaced)) {
content_rect =
LayoutReplaced::PreSnappedRectForPersistentSizing(content_rect);
}
// LayoutReplaced clips the foreground by rounded content box.
- state.clip_rect = replaced.StyleRef().GetRoundedInnerBorderFor(
+ auto clip_rect = replaced.StyleRef().GetRoundedInnerBorderFor(
content_rect.ToLayoutRect(),
LayoutRectOutsets(
-(replaced.PaddingTop() + replaced.BorderTop()),
-(replaced.PaddingRight() + replaced.BorderRight()),
-(replaced.PaddingBottom() + replaced.BorderBottom()),
-(replaced.PaddingLeft() + replaced.BorderLeft())));
+ state.SetClipRect(clip_rect, clip_rect);
if (replaced.IsLayoutEmbeddedContent()) {
// Embedded objects are always sized to fit the content rect, but they
// could overflow by 1px due to pre-snapping. Adjust clip rect to
// match pre-snapped box as a special case.
- FloatRect adjusted_rect = state.clip_rect.Rect();
+ FloatRect adjusted_rect = clip_rect.Rect();
adjusted_rect.SetSize(FloatSize(replaced.ReplacedContentRect().size));
- state.clip_rect.SetRect(adjusted_rect);
+ FloatRoundedRect adjusted_clip_rect(adjusted_rect,
+ clip_rect.GetRadii());
+ state.SetClipRect(adjusted_clip_rect, adjusted_clip_rect);
}
} else if (object_.IsBox()) {
- state.clip_rect = ToSnappedClipRect(OverflowClipRect(
- ToLayoutBox(object_), context_.current.paint_offset));
- state.clip_rect_excluding_overlay_scrollbars = FloatClipRect(
- FloatRect(PixelSnappedIntRect(ToLayoutBox(object_).OverflowClipRect(
+ const auto& clip_rect = OverflowClipRect(ToLayoutBox(object_),
+ context_.current.paint_offset);
+ state.SetClipRect(FloatRoundedRect(FloatRect(clip_rect)),
+ ToSnappedClipRect(clip_rect));
+
+ state.clip_rect_excluding_overlay_scrollbars =
+ FloatClipRect(FloatRect(ToLayoutBox(object_).OverflowClipRect(
context_.current.paint_offset,
- kExcludeOverlayScrollbarSizeForHitTesting))));
+ kExcludeOverlayScrollbarSizeForHitTesting)));
} else {
DCHECK(object_.IsSVGViewportContainer());
const auto& viewport_container = ToLayoutSVGViewportContainer(object_);
- state.clip_rect = FloatRoundedRect(
+ const auto clip_rect = FloatRoundedRect(
viewport_container.LocalToSVGParentTransform().Inverse().MapRect(
viewport_container.Viewport()));
+ state.SetClipRect(clip_rect, clip_rect);
}
OnUpdateClip(properties_->UpdateOverflowClip(*context_.current.clip,
std::move(state)));
@@ -1687,14 +1734,6 @@ void FragmentPaintPropertyTreeBuilder::UpdatePerspective() {
}
}
-static bool ImageWasTransposed(const LayoutImage& layout_image,
- const Image& image) {
- return LayoutObject::ShouldRespectImageOrientation(&layout_image) ==
- kRespectImageOrientation &&
- image.IsBitmapImage() &&
- ToBitmapImage(image).CurrentFrameOrientation().UsesWidthAsHeight();
-}
-
static AffineTransform RectToRect(const FloatRect& src_rect,
const FloatRect& dst_rect) {
float x_scale = dst_rect.Width() / src_rect.Width();
@@ -1723,9 +1762,9 @@ void FragmentPaintPropertyTreeBuilder::UpdateReplacedContentTransform() {
scoped_refptr<Image> image =
layout_image.ImageResource()->GetImage(replaced_rect.Size());
if (image && !image->IsNull()) {
- IntRect src_rect = image->Rect();
- if (ImageWasTransposed(layout_image, *image))
- src_rect = src_rect.TransposedRect();
+ IntRect src_rect(
+ IntPoint(), image->Size(LayoutObject::ShouldRespectImageOrientation(
+ &layout_image)));
content_to_parent_space =
RectToRect(FloatRect(src_rect), FloatRect(replaced_rect));
}
@@ -1733,8 +1772,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateReplacedContentTransform() {
NOTREACHED();
}
if (!content_to_parent_space.IsIdentity()) {
- TransformPaintPropertyNode::State state{
- TransformationMatrix(content_to_parent_space)};
+ TransformPaintPropertyNode::State state;
+ SetTransformNodeStateFromAffineTransform(state, content_to_parent_space);
state.flags.flattens_inherited_transform =
context_.current.should_flatten_inherited_transform;
OnUpdate(properties_->UpdateReplacedContentTransform(
@@ -1769,7 +1808,7 @@ static MainThreadScrollingReasons GetMainThreadScrollingReasons(
if (!object.IsBox())
return reasons;
- if (object.IsLayoutView()) {
+ if (IsA<LayoutView>(object)) {
if (object.GetFrameView()
->RequiresMainThreadScrollingForBackgroundAttachmentFixed()) {
reasons |=
@@ -1819,7 +1858,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
DCHECK(properties_);
if (NeedsPaintPropertyUpdate()) {
- if (NeedsScrollNode(object_, full_context_.direct_compositing_reasons)) {
+ if (object_.IsBox() && ToLayoutBox(object_).NeedsScrollNode(
+ full_context_.direct_compositing_reasons)) {
const LayoutBox& box = ToLayoutBox(object_);
PaintLayerScrollableArea* scrollable_area = box.GetScrollableArea();
ScrollPaintPropertyNode::State state;
@@ -1837,8 +1877,6 @@ void FragmentPaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation() {
state.user_scrollable_vertical =
scrollable_area->UserInputScrollable(kVerticalScrollbar);
- state.scrolls_outer_viewport = box.IsGlobalRootScroller();
-
// TODO(bokan): We probably don't need to pass ancestor reasons down the
// scroll tree. On the compositor, in
// LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint, we walk up
@@ -1981,7 +2019,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateOutOfFlowContext() {
if (object_.CanContainAbsolutePositionObjects())
context_.absolute_position = context_.current;
- if (object_.IsLayoutView()) {
+ if (IsA<LayoutView>(object_)) {
const auto* initial_fixed_transform = context_.fixed_position.transform;
context_.fixed_position = context_.current;
@@ -2020,8 +2058,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateOutOfFlowContext() {
if (NeedsPaintPropertyUpdate()) {
OnUpdate(properties_->UpdateCssClipFixedPosition(
*context_.fixed_position.clip,
- ClipPaintPropertyNode::State{&css_clip->LocalTransformSpace(),
- css_clip->ClipRect()}));
+ ClipPaintPropertyNode::State(&css_clip->LocalTransformSpace(),
+ css_clip->PixelSnappedClipRect())));
}
if (properties_->CssClipFixedPosition())
context_.fixed_position.clip = properties_->CssClipFixedPosition();
@@ -2202,48 +2240,104 @@ static PhysicalOffset PaintOffsetInPaginationContainer(
}
void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
- // Paint offsets for fragmented content are computed from scratch.
- const auto* enclosing_pagination_layer =
- full_context_.painting_layer->EnclosingPaginationLayer();
- if (enclosing_pagination_layer &&
- // Except if the paint_offset_root is below the pagination container,
- // in which case fragmentation offsets are already baked into the paint
- // offset transform for paint_offset_root.
- !context_.current.paint_offset_root->PaintingLayer()
- ->EnclosingPaginationLayer()) {
- // Set fragment visual paint offset.
- PhysicalOffset paint_offset =
- PaintOffsetInPaginationContainer(object_, *enclosing_pagination_layer);
-
- paint_offset += fragment_data_.PaginationOffset();
- paint_offset += context_.repeating_paint_offset_adjustment;
- paint_offset +=
- VisualOffsetFromPaintOffsetRoot(context_, enclosing_pagination_layer);
-
- // The paint offset root can have a subpixel paint offset adjustment.
- // The paint offset root always has one fragment.
- const auto& paint_offset_root_fragment =
- context_.current.paint_offset_root->FirstFragment();
- paint_offset += paint_offset_root_fragment.PaintOffset();
-
- context_.current.paint_offset = paint_offset;
- return;
- }
+ if (!IsInNGFragmentTraversal()) {
+ // Paint offsets for fragmented content are computed from scratch.
+ const auto* enclosing_pagination_layer =
+ full_context_.painting_layer->EnclosingPaginationLayer();
+ if (enclosing_pagination_layer &&
+ // Except if the paint_offset_root is below the pagination container, in
+ // which case fragmentation offsets are already baked into the paint
+ // offset transform for paint_offset_root.
+ !context_.current.paint_offset_root->PaintingLayer()
+ ->EnclosingPaginationLayer()) {
+ // Set fragment visual paint offset.
+ PhysicalOffset paint_offset = PaintOffsetInPaginationContainer(
+ object_, *enclosing_pagination_layer);
+
+ paint_offset += fragment_data_.LegacyPaginationOffset();
+ paint_offset += context_.repeating_paint_offset_adjustment;
+ paint_offset +=
+ VisualOffsetFromPaintOffsetRoot(context_, enclosing_pagination_layer);
+
+ // The paint offset root can have a subpixel paint offset adjustment.
+ // The paint offset root always has one fragment.
+ const auto& paint_offset_root_fragment =
+ context_.current.paint_offset_root->FirstFragment();
+ paint_offset += paint_offset_root_fragment.PaintOffset();
+
+ context_.current.paint_offset = paint_offset;
+ return;
+ }
- if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
- context_.current.paint_offset = context_.paint_offset_for_float;
+ if (object_.IsFloating() && !object_.IsInLayoutNGInlineFormattingContext())
+ context_.current.paint_offset = context_.paint_offset_for_float;
- // Multicolumn spanners are painted starting at the multicolumn container (but
- // still inherit properties in layout-tree order) so reset the paint offset.
- if (object_.IsColumnSpanAll()) {
- context_.current.paint_offset =
- object_.Container()->FirstFragment().PaintOffset();
+ // Multicolumn spanners are painted starting at the multicolumn container
+ // (but still inherit properties in layout-tree order) so reset the paint
+ // offset.
+ if (object_.IsColumnSpanAll()) {
+ context_.current.paint_offset =
+ object_.Container()->FirstFragment().PaintOffset();
+ }
}
if (object_.IsBoxModelObject()) {
const LayoutBoxModelObject& box_model_object =
ToLayoutBoxModelObject(object_);
- switch (box_model_object.StyleRef().GetPosition()) {
+ EPosition position = box_model_object.StyleRef().GetPosition();
+ if (IsInNGFragmentTraversal() &&
+ (position == EPosition::kAbsolute || position == EPosition::kFixed)) {
+ // The LayoutNG fragment tree structure is very similar to the containing
+ // block structure, with the exception of out-of-flow positioned boxes
+ // whose containing block is a non-atomic inline. If this is the case, we
+ // now need to add the offsets introduced by all inlines in the ancestry
+ // that affect us. This is a way to work around the discrepancy between
+ // the NG fragment tree structure and the actual containing block tree
+ // structure.
+ // TODO(mstensho): It's not good to walk up the ancestry
+ // (LayoutObject::Container()) like this, in fact pretty disastrous for
+ // e.g. fixed positioned objects, whose containing block is typically far
+ // up in the tree. Should we introduce a bit on LayoutObject that's set
+ // when this is necessary (or likely to be necessary)?
+ const LayoutObject* container = object_.Container();
+ if (container->IsLayoutInline() || container->IsAnonymousBlock()) {
+ // Set up context_ and full_context_ to be aware of the inline that is
+ // the actual containing block. This will be used by the code further
+ // down in this method.
+ // TODO(mstensho): This is currently incomplete. We're failing cases
+ // where the containing block sets up a filter, for instance.
+ if (position == EPosition::kFixed)
+ full_context_.container_for_fixed_position = container;
+ full_context_.container_for_absolute_position = container;
+ PhysicalOffset relative_offset;
+ if (const LayoutBox* box = ToLayoutBoxOrNull(container)) {
+ // If the OOF is contained by an anonymous block (because of inline
+ // continuations), we need to take that into account.
+ //
+ // Example:
+ // <span style="position:relative;">
+ // <div>
+ // <div id="box_model_object" style="position:absolute;">
+ DCHECK(box->IsAnonymousBlock());
+ relative_offset =
+ box->PhysicalLocation() + box->OffsetForInFlowPosition();
+ } else {
+ do {
+ relative_offset +=
+ ToLayoutInline(container)->OffsetForInFlowPosition();
+ container = container->Container();
+ } while (container->IsLayoutInline());
+ }
+ if (position == EPosition::kFixed) {
+ context_.fixed_position = context_.current;
+ context_.fixed_position.paint_offset += relative_offset;
+ }
+ context_.absolute_position = context_.current;
+ context_.absolute_position.paint_offset += relative_offset;
+ }
+ }
+
+ switch (position) {
case EPosition::kStatic:
break;
case EPosition::kRelative:
@@ -2294,6 +2388,15 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffset() {
}
}
+ if (IsInNGFragmentTraversal()) {
+ // Text and non-atomic inlines are special, in that they share one
+ // FragmentData per fragmentainer, so their paint offset is kept at their
+ // container. For all other objects, include the offset now.
+ if (object_.IsBox())
+ context_.current.paint_offset += pre_paint_info_->iterator->Link().offset;
+ return;
+ }
+
if (object_.IsBox()) {
// TODO(pdr): Several calls in this function walk back up the tree to
// calculate containers (e.g., physicalLocation, offsetForInFlowPosition*).
@@ -2396,6 +2499,14 @@ void FragmentPaintPropertyTreeBuilder::UpdateForObjectLocationAndSize(
fragment_data_.SetPaintOffset(context_.current.paint_offset);
fragment_data_.InvalidateClipPathCache();
+ if (object_.IsBox()) {
+ // See PaintLayerScrollableArea::PixelSnappedBorderBoxRect() for the
+ // reason of this.
+ if (auto* scrollable_area = ToLayoutBox(object_).GetScrollableArea())
+ scrollable_area->PositionOverflowControls();
+ }
+
+ object_.GetMutableForPainting().InvalidateIntersectionObserverCachedRects();
object_.GetFrameView()->SetIntersectionObservationState(
LocalFrameView::kDesired);
}
@@ -2513,9 +2624,7 @@ void FragmentPaintPropertyTreeBuilder::UpdateForChildren() {
void PaintPropertyTreeBuilder::InitFragmentPaintProperties(
FragmentData& fragment,
- bool needs_paint_properties,
- const PhysicalOffset& pagination_offset,
- LayoutUnit logical_top_in_flow_thread) {
+ bool needs_paint_properties) {
if (needs_paint_properties) {
fragment.EnsurePaintProperties();
} else if (fragment.PaintProperties()) {
@@ -2524,16 +2633,35 @@ void PaintPropertyTreeBuilder::InitFragmentPaintProperties(
PaintPropertyTreeBuilderContext::kSubtreeUpdateIsolationBlocked;
fragment.ClearPaintProperties();
}
- fragment.SetPaginationOffset(pagination_offset);
+}
+
+void PaintPropertyTreeBuilder::InitFragmentPaintPropertiesForLegacy(
+ FragmentData& fragment,
+ bool needs_paint_properties,
+ const PhysicalOffset& pagination_offset,
+ LayoutUnit logical_top_in_flow_thread) {
+ DCHECK(!IsInNGFragmentTraversal());
+ InitFragmentPaintProperties(fragment, needs_paint_properties);
+ fragment.SetLegacyPaginationOffset(pagination_offset);
fragment.SetLogicalTopInFlowThread(logical_top_in_flow_thread);
}
+void PaintPropertyTreeBuilder::InitFragmentPaintPropertiesForNG(
+ bool needs_paint_properties) {
+ InitFragmentPaintProperties(pre_paint_info_->fragment_data,
+ needs_paint_properties);
+ if (context_.fragments.IsEmpty())
+ context_.fragments.push_back(PaintPropertyTreeBuilderFragmentContext());
+ else
+ context_.fragments.resize(1);
+}
+
void PaintPropertyTreeBuilder::InitSingleFragmentFromParent(
bool needs_paint_properties) {
FragmentData& first_fragment =
object_.GetMutableForPainting().FirstFragment();
first_fragment.ClearNextFragment();
- InitFragmentPaintProperties(first_fragment, needs_paint_properties);
+ InitFragmentPaintPropertiesForLegacy(first_fragment, needs_paint_properties);
if (context_.fragments.IsEmpty()) {
context_.fragments.push_back(PaintPropertyTreeBuilderFragmentContext());
} else {
@@ -2591,6 +2719,7 @@ void PaintPropertyTreeBuilder::InitSingleFragmentFromParent(
}
void PaintPropertyTreeBuilder::UpdateCompositedLayerPaginationOffset() {
+ DCHECK(!IsInNGFragmentTraversal());
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
return;
@@ -2620,7 +2749,7 @@ void PaintPropertyTreeBuilder::UpdateCompositedLayerPaginationOffset() {
BoundingBoxInPaginationContainer(object_, *enclosing_pagination_layer)
.ToLayoutRect());
if (!iterator.AtEnd()) {
- first_fragment.SetPaginationOffset(
+ first_fragment.SetLegacyPaginationOffset(
PhysicalOffsetToBeNoop(iterator.PaginationOffset()));
first_fragment.SetLogicalTopInFlowThread(
iterator.FragmentainerLogicalTopInFlowThread());
@@ -2629,7 +2758,7 @@ void PaintPropertyTreeBuilder::UpdateCompositedLayerPaginationOffset() {
// All objects under the composited layer use the same pagination offset.
const auto& fragment =
parent_composited_layer->GetLayoutObject().FirstFragment();
- first_fragment.SetPaginationOffset(fragment.PaginationOffset());
+ first_fragment.SetLegacyPaginationOffset(fragment.LegacyPaginationOffset());
first_fragment.SetLogicalTopInFlowThread(fragment.LogicalTopInFlowThread());
}
}
@@ -2867,6 +2996,7 @@ PaintPropertyTreeBuilderFragmentContext
PaintPropertyTreeBuilder::ContextForFragment(
const base::Optional<PhysicalRect>& fragment_clip,
LayoutUnit logical_top_in_flow_thread) const {
+ DCHECK(!IsInNGFragmentTraversal());
const auto& parent_fragments = context_.fragments;
if (parent_fragments.IsEmpty())
return PaintPropertyTreeBuilderFragmentContext();
@@ -2977,6 +3107,7 @@ PaintPropertyTreeBuilder::ContextForFragment(
void PaintPropertyTreeBuilder::CreateFragmentContextsInFlowThread(
bool needs_paint_properties) {
+ DCHECK(!IsInNGFragmentTraversal());
// We need at least the fragments for all fragmented objects, which store
// their local border box properties and paint invalidation data (such
// as paint offset and visual rect) on each fragment.
@@ -3068,11 +3199,11 @@ void PaintPropertyTreeBuilder::CreateFragmentContextsInFlowThread(
new_fragment_contexts.back().fragment_clip;
fragments_changed = !!old_fragment_clip != !!new_fragment_clip ||
(old_fragment_clip && new_fragment_clip &&
- old_fragment_clip->ClipRect() !=
+ old_fragment_clip->PixelSnappedClipRect() !=
ToSnappedClipRect(*new_fragment_clip));
}
- InitFragmentPaintProperties(
+ InitFragmentPaintPropertiesForLegacy(
*current_fragment_data,
needs_paint_properties || new_fragment_contexts.back().fragment_clip,
pagination_offset, logical_top_in_flow_thread);
@@ -3190,9 +3321,9 @@ void PaintPropertyTreeBuilder::CreateFragmentDataForRepeatingInPagedMedia(
fragment_data = fragment_data
? &fragment_data->EnsureNextFragment()
: &object_.GetMutableForPainting().FirstFragment();
- InitFragmentPaintProperties(*fragment_data, needs_paint_properties,
- PhysicalOffset(),
- fragment_context.logical_top_in_flow_thread);
+ InitFragmentPaintPropertiesForLegacy(
+ *fragment_data, needs_paint_properties, PhysicalOffset(),
+ fragment_context.logical_top_in_flow_thread);
}
DCHECK(fragment_data);
fragment_data->ClearNextFragment();
@@ -3215,7 +3346,7 @@ bool PaintPropertyTreeBuilder::UpdateFragments() {
// the paint offset and border box has been computed.
MayNeedClipPathClip(object_) ||
NeedsEffect(object_, context_.direct_compositing_reasons) ||
- NeedsTransformForNonRootSVG(object_) ||
+ NeedsTransformForSVGChild(object_) ||
NeedsFilter(object_, context_.direct_compositing_reasons) ||
NeedsCssClip(object_) || NeedsInnerBorderRadiusClip(object_) ||
NeedsOverflowClip(object_) || NeedsPerspective(object_) ||
@@ -3229,25 +3360,29 @@ bool PaintPropertyTreeBuilder::UpdateFragments() {
// Need of fragmentation clip will be determined in CreateFragmentContexts().
- if (object_.IsFixedPositionObjectInPagedMedia()) {
- // This flag applies to the object itself and descendants.
- context_.is_repeating_fixed_position = true;
- CreateFragmentContextsForRepeatingFixedPosition();
- } else if (ObjectIsRepeatingTableSectionInPagedMedia()) {
- context_.repeating_table_section =
- &ToInterface<LayoutNGTableSectionInterface>(object_);
- CreateFragmentContextsForRepeatingTableSectionInPagedMedia();
- }
-
- if (IsRepeatingInPagedMedia()) {
- CreateFragmentDataForRepeatingInPagedMedia(needs_paint_properties);
- } else if (context_.painting_layer->ShouldFragmentCompositedBounds()) {
- CreateFragmentContextsInFlowThread(needs_paint_properties);
+ if (IsInNGFragmentTraversal()) {
+ InitFragmentPaintPropertiesForNG(needs_paint_properties);
} else {
- InitSingleFragmentFromParent(needs_paint_properties);
- UpdateCompositedLayerPaginationOffset();
- context_.is_repeating_fixed_position = false;
- context_.repeating_table_section = nullptr;
+ if (object_.IsFixedPositionObjectInPagedMedia()) {
+ // This flag applies to the object itself and descendants.
+ context_.is_repeating_fixed_position = true;
+ CreateFragmentContextsForRepeatingFixedPosition();
+ } else if (ObjectIsRepeatingTableSectionInPagedMedia()) {
+ context_.repeating_table_section =
+ &ToInterface<LayoutNGTableSectionInterface>(object_);
+ CreateFragmentContextsForRepeatingTableSectionInPagedMedia();
+ }
+
+ if (IsRepeatingInPagedMedia()) {
+ CreateFragmentDataForRepeatingInPagedMedia(needs_paint_properties);
+ } else if (context_.painting_layer->ShouldFragmentCompositedBounds()) {
+ CreateFragmentContextsInFlowThread(needs_paint_properties);
+ } else {
+ InitSingleFragmentFromParent(needs_paint_properties);
+ UpdateCompositedLayerPaginationOffset();
+ context_.is_repeating_fixed_position = false;
+ context_.repeating_table_section = nullptr;
+ }
}
if (object_.IsSVGHiddenContainer()) {
@@ -3272,7 +3407,8 @@ bool PaintPropertyTreeBuilder::UpdateFragments() {
context_.has_svg_hidden_container_ancestor);
}
- UpdateRepeatingTableSectionPaintOffsetAdjustment();
+ if (!IsInNGFragmentTraversal())
+ UpdateRepeatingTableSectionPaintOffsetAdjustment();
return needs_paint_properties != had_paint_properties;
}
@@ -3288,17 +3424,15 @@ bool PaintPropertyTreeBuilder::ObjectTypeMightNeedMultipleFragmentData() const {
}
void PaintPropertyTreeBuilder::UpdatePaintingLayer() {
- bool changed_painting_layer = false;
if (object_.HasLayer() &&
ToLayoutBoxModelObject(object_).HasSelfPaintingLayer()) {
context_.painting_layer = ToLayoutBoxModelObject(object_).Layer();
- changed_painting_layer = true;
- } else if (object_.IsColumnSpanAll() ||
- object_.IsFloatingWithNonContainingBlockParent()) {
+ } else if (!IsInNGFragmentTraversal() &&
+ (object_.IsColumnSpanAll() ||
+ object_.IsFloatingWithNonContainingBlockParent())) {
// See LayoutObject::paintingLayer() for the special-cases of floating under
// inline and multicolumn.
context_.painting_layer = object_.PaintingLayer();
- changed_painting_layer = true;
}
DCHECK(context_.painting_layer == object_.PaintingLayer());
}
@@ -3318,22 +3452,48 @@ PaintPropertyChangeType PaintPropertyTreeBuilder::UpdateForSelf() {
property_changed = PaintPropertyChangeType::kNodeAddedOrRemoved;
} else {
DCHECK_EQ(context_.direct_compositing_reasons, CompositingReason::kNone);
- object_.GetMutableForPainting().FirstFragment().ClearNextFragment();
+ if (!IsInNGFragmentTraversal())
+ object_.GetMutableForPainting().FirstFragment().ClearNextFragment();
}
- auto* fragment_data = &object_.GetMutableForPainting().FirstFragment();
- for (auto& fragment_context : context_.fragments) {
- FragmentPaintPropertyTreeBuilder builder(object_, context_,
- fragment_context, *fragment_data);
+ if (pre_paint_info_) {
+ DCHECK_EQ(context_.fragments.size(), 1u);
+ FragmentPaintPropertyTreeBuilder builder(object_, pre_paint_info_, context_,
+ context_.fragments[0],
+ pre_paint_info_->fragment_data);
builder.UpdateForSelf();
property_changed = std::max(property_changed, builder.PropertyChanged());
- fragment_data = fragment_data->NextFragment();
+ } else {
+ auto* fragment_data = &object_.GetMutableForPainting().FirstFragment();
+ for (auto& fragment_context : context_.fragments) {
+ FragmentPaintPropertyTreeBuilder builder(
+ object_, /* pre_paint_info */ nullptr, context_, fragment_context,
+ *fragment_data);
+ builder.UpdateForSelf();
+ property_changed = std::max(property_changed, builder.PropertyChanged());
+ fragment_data = fragment_data->NextFragment();
+ }
+ DCHECK(!fragment_data);
}
- DCHECK(!fragment_data);
// We need to update property tree states of paint chunks.
if (property_changed >= PaintPropertyChangeType::kNodeAddedOrRemoved) {
context_.painting_layer->SetNeedsRepaint();
+ if (object_.IsDocumentElement()) {
+ // View background painting depends on existence of the document element's
+ // paint properties (see callsite of ViewPainter::PaintRootGroup()).
+ // Invalidate view background display item clients.
+ // SetBackgroundNeedsFullPaintInvalidation() won't work here because we
+ // have already walked the LayoutView in PrePaintTreeWalk.
+ LayoutView* layout_view = object_.View();
+ layout_view->Layer()->SetNeedsRepaint();
+ auto reason = PaintInvalidationReason::kBackground;
+ static_cast<const DisplayItemClient*>(layout_view)->Invalidate(reason);
+ if (auto* scrollable_area = layout_view->GetScrollableArea()) {
+ scrollable_area->GetScrollingBackgroundDisplayItemClient().Invalidate(
+ reason);
+ }
+ }
}
return property_changed;
@@ -3345,13 +3505,21 @@ PaintPropertyChangeType PaintPropertyTreeBuilder::UpdateForChildren() {
if (!ObjectTypeMightNeedPaintProperties())
return property_changed;
- auto* fragment_data = &object_.GetMutableForPainting().FirstFragment();
+ FragmentData* fragment_data;
+ if (pre_paint_info_) {
+ DCHECK_EQ(context_.fragments.size(), 1u);
+ fragment_data = &pre_paint_info_->fragment_data;
+ DCHECK(fragment_data);
+ } else {
+ fragment_data = &object_.GetMutableForPainting().FirstFragment();
+ }
+
// For now, only consider single fragment elements as possible isolation
// boundaries.
// TODO(crbug.com/890932): See if this is needed.
bool is_isolated = context_.fragments.size() == 1u;
for (auto& fragment_context : context_.fragments) {
- FragmentPaintPropertyTreeBuilder builder(object_, context_,
+ FragmentPaintPropertyTreeBuilder builder(object_, pre_paint_info_, context_,
fragment_context, *fragment_data);
// The element establishes an isolation boundary if it has isolation nodes
// before and after updating the children. In other words, if it didn't have
@@ -3364,7 +3532,12 @@ PaintPropertyChangeType PaintPropertyTreeBuilder::UpdateForChildren() {
property_changed = std::max(property_changed, builder.PropertyChanged());
fragment_data = fragment_data->NextFragment();
}
- DCHECK(!fragment_data);
+
+ // With NG fragment traversal we were supplied with the right FragmentData by
+ // the caller, and we only ran one lap in the loop above. Whether or not there
+ // are more FragmentData objects following is irrelevant then.
+ DCHECK(pre_paint_info_ || !fragment_data);
+
if (object_.SubtreePaintPropertyUpdateReasons() !=
static_cast<unsigned>(SubtreePaintPropertyUpdateReason::kNone)) {
if (AreSubtreeUpdateReasonsIsolationPiercing(
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
index 812cb587cc8..22e4495fda1 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder.h
@@ -20,6 +20,7 @@ class FragmentData;
class LayoutObject;
class LayoutNGTableSectionInterface;
class LocalFrameView;
+class NGFragmentChildIterator;
class PaintLayer;
class VisualViewport;
@@ -194,6 +195,18 @@ class VisualViewportPaintPropertyTreeBuilder {
PaintPropertyTreeBuilderContext&);
};
+struct NGPrePaintInfo {
+ STACK_ALLOCATED();
+
+ public:
+ NGPrePaintInfo(const NGFragmentChildIterator& iterator,
+ FragmentData& fragment_data)
+ : iterator(iterator), fragment_data(fragment_data) {}
+
+ const NGFragmentChildIterator& iterator;
+ FragmentData& fragment_data;
+};
+
// Creates paint property tree nodes for non-local effects in the layout tree.
// Non-local effects include but are not limited to: overflow clip, transform,
// fixed-pos, animation, mask, filters, etc. It expects to be invoked for each
@@ -206,8 +219,9 @@ class PaintPropertyTreeBuilder {
PaintPropertyTreeBuilderContext&);
PaintPropertyTreeBuilder(const LayoutObject& object,
+ NGPrePaintInfo* pre_paint_info,
PaintPropertyTreeBuilderContext& context)
- : object_(object), context_(context) {}
+ : object_(object), pre_paint_info_(pre_paint_info), context_(context) {}
// Update the paint properties that affect this object (e.g., properties like
// paint offset translation) and ensure the context is up to date. Also
@@ -221,11 +235,15 @@ class PaintPropertyTreeBuilder {
PaintPropertyChangeType UpdateForChildren();
private:
- ALWAYS_INLINE void InitFragmentPaintProperties(
+ ALWAYS_INLINE void InitFragmentPaintProperties(FragmentData&,
+ bool needs_paint_properties);
+ ALWAYS_INLINE void InitFragmentPaintPropertiesForLegacy(
FragmentData&,
bool needs_paint_properties,
const PhysicalOffset& pagination_offset = PhysicalOffset(),
LayoutUnit logical_top_in_flow_thread = LayoutUnit());
+ ALWAYS_INLINE void InitFragmentPaintPropertiesForNG(
+ bool needs_paint_properties);
ALWAYS_INLINE void InitSingleFragmentFromParent(bool needs_paint_properties);
ALWAYS_INLINE bool ObjectTypeMightNeedMultipleFragmentData() const;
ALWAYS_INLINE bool ObjectTypeMightNeedPaintProperties() const;
@@ -249,7 +267,11 @@ class PaintPropertyTreeBuilder {
ALWAYS_INLINE void UpdateRepeatingTableHeaderPaintOffsetAdjustment();
ALWAYS_INLINE void UpdateRepeatingTableFooterPaintOffsetAdjustment();
+ bool IsInNGFragmentTraversal() const { return pre_paint_info_; }
+
const LayoutObject& object_;
+ NGPrePaintInfo* pre_paint_info_;
+
PaintPropertyTreeBuilderContext& context_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 030a1f0ed31..1805b3db5f4 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -135,8 +135,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FixedPosition) {
transformed_scroll->setScrollTop(5);
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
// target1 is a fixed-position element inside an absolute-position scrolling
// element. It should be attached under the viewport to skip scrolling and
@@ -145,7 +144,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FixedPosition) {
const ObjectPaintProperties* target1_properties =
target1->GetLayoutObject()->FirstFragment().PaintProperties();
EXPECT_EQ(FloatRoundedRect(200, 150, 100, 100),
- target1_properties->OverflowClip()->ClipRect());
+ target1_properties->OverflowClip()->UnsnappedClipRect());
// Likewise, it inherits clip from the viewport, skipping overflow clip of the
// scroller.
EXPECT_EQ(DocContentClip(), target1_properties->OverflowClip()->Parent());
@@ -172,7 +171,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FixedPosition) {
const ObjectPaintProperties* scroller_properties =
scroller->GetLayoutObject()->FirstFragment().PaintProperties();
EXPECT_EQ(FloatRoundedRect(200, 150, 100, 100),
- target2_properties->OverflowClip()->ClipRect());
+ target2_properties->OverflowClip()->UnsnappedClipRect());
EXPECT_EQ(scroller_properties->OverflowClip(),
target2_properties->OverflowClip()->Parent());
// target2 should not have it's own scroll node and instead should inherit
@@ -198,8 +197,7 @@ TEST_P(PaintPropertyTreeBuilderTest, PositionAndScroll) {
Element* scroller = GetDocument().getElementById("scroller");
scroller->scrollTo(0, 100);
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
const ObjectPaintProperties* scroller_properties =
scroller->GetLayoutObject()->FirstFragment().PaintProperties();
EXPECT_EQ(FloatSize(0, -100),
@@ -219,7 +217,7 @@ TEST_P(PaintPropertyTreeBuilderTest, PositionAndScroll) {
EXPECT_EQ(FloatSize(120, 340),
scroller_properties->PaintOffsetTranslation()->Translation2D());
EXPECT_EQ(FloatRoundedRect(0, 0, 413, 317),
- scroller_properties->OverflowClip()->ClipRect());
+ scroller_properties->OverflowClip()->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(), scroller_properties->OverflowClip()->Parent());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(120, 340, 413, 317),
scroller->GetLayoutObject(),
@@ -237,7 +235,7 @@ TEST_P(PaintPropertyTreeBuilderTest, PositionAndScroll) {
EXPECT_EQ(rel_pos_properties->Transform(),
&rel_pos_properties->OverflowClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(0, 0, 100, 200),
- rel_pos_properties->OverflowClip()->ClipRect());
+ rel_pos_properties->OverflowClip()->UnsnappedClipRect());
EXPECT_EQ(scroller_properties->OverflowClip(),
rel_pos_properties->OverflowClip()->Parent());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(), rel_pos->GetLayoutObject(),
@@ -255,7 +253,7 @@ TEST_P(PaintPropertyTreeBuilderTest, PositionAndScroll) {
EXPECT_EQ(abs_pos_properties->Transform(),
&abs_pos_properties->OverflowClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(0, 0, 300, 400),
- abs_pos_properties->OverflowClip()->ClipRect());
+ abs_pos_properties->OverflowClip()->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(), abs_pos_properties->OverflowClip()->Parent());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(123, 456, 300, 400),
abs_pos->GetLayoutObject(),
@@ -278,7 +276,8 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollExcludeScrollbars) {
EXPECT_EQ(DocContentClip(), overflow_clip->Parent());
EXPECT_EQ(properties->PaintOffsetTranslation(),
&overflow_clip->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(10, 10, 100, 100), overflow_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(10, 10, 100, 100),
+ overflow_clip->UnsnappedClipRect());
PaintLayer* paint_layer =
ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"))->Layer();
@@ -287,7 +286,7 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollExcludeScrollbars) {
->IsOverlayScrollbar());
EXPECT_EQ(FloatClipRect(FloatRect(10, 10, 93, 93)),
- overflow_clip->ClipRectExcludingOverlayScrollbars());
+ overflow_clip->UnsnappedClipRectExcludingOverlayScrollbars());
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollExcludeScrollbarsSubpixel) {
@@ -307,15 +306,18 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollExcludeScrollbarsSubpixel) {
EXPECT_EQ(DocContentClip(), overflow_clip->Parent());
EXPECT_EQ(properties->PaintOffsetTranslation(),
&overflow_clip->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(10, 10, 101, 100), overflow_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(10, 10, 100.5, 100),
+ overflow_clip->UnsnappedClipRect());
+ EXPECT_EQ(FloatRoundedRect(10, 10, 101, 100),
+ overflow_clip->PixelSnappedClipRect());
EXPECT_TRUE(ToLayoutBox(scroller)
->GetScrollableArea()
->VerticalScrollbar()
->IsOverlayScrollbar());
- EXPECT_EQ(FloatClipRect(FloatRect(10, 10, 94, 93)),
- overflow_clip->ClipRectExcludingOverlayScrollbars());
+ EXPECT_EQ(FloatClipRect(FloatRect(10, 10, 93.5, 93)),
+ overflow_clip->UnsnappedClipRectExcludingOverlayScrollbars());
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollExcludeCssOverlayScrollbar) {
@@ -335,7 +337,8 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollExcludeCssOverlayScrollbar) {
)HTML");
// The document content should not be clipped by the overlay scrollbar because
// the scrollbar can be transparent and the content needs to paint below.
- EXPECT_EQ(DocContentClip()->ClipRect(), FloatRoundedRect(0, 0, 800, 600));
+ EXPECT_EQ(DocContentClip()->UnsnappedClipRect(),
+ FloatRoundedRect(0, 0, 800, 600));
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRL) {
@@ -368,9 +371,11 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRL) {
EXPECT_EQ(DocContentClip(), overflow_clip->Parent());
EXPECT_EQ(properties->PaintOffsetTranslation(),
&overflow_clip->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(10, 10, 85, 85), overflow_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(10, 10, 85, 85),
+ overflow_clip->UnsnappedClipRect());
- scroller->GetScrollableArea()->ScrollBy(ScrollOffset(-100, 0), kUserScroll);
+ scroller->GetScrollableArea()->ScrollBy(ScrollOffset(-100, 0),
+ mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
// Only scroll_translation is affected by scrolling.
@@ -386,7 +391,8 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRL) {
EXPECT_EQ(DocContentClip(), overflow_clip->Parent());
EXPECT_EQ(properties->PaintOffsetTranslation(),
&overflow_clip->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(10, 10, 85, 85), overflow_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(10, 10, 85, 85),
+ overflow_clip->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollRTL) {
@@ -420,9 +426,11 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollRTL) {
EXPECT_EQ(DocContentClip(), overflow_clip->Parent());
EXPECT_EQ(properties->PaintOffsetTranslation(),
&overflow_clip->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(25, 10, 85, 85), overflow_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(25, 10, 85, 85),
+ overflow_clip->UnsnappedClipRect());
- scroller->GetScrollableArea()->ScrollBy(ScrollOffset(-100, 0), kUserScroll);
+ scroller->GetScrollableArea()->ScrollBy(ScrollOffset(-100, 0),
+ mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
// Only scroll_translation is affected by scrolling.
@@ -438,7 +446,8 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollRTL) {
EXPECT_EQ(DocContentClip(), overflow_clip->Parent());
EXPECT_EQ(properties->PaintOffsetTranslation(),
&overflow_clip->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(25, 10, 85, 85), overflow_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(25, 10, 85, 85),
+ overflow_clip->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRLMulticol) {
@@ -462,7 +471,7 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRLMulticol) {
EXPECT_EQ(410, FragmentAt(flow_thread, 0)
.PaintProperties()
->FragmentClip()
- ->ClipRect()
+ ->UnsnappedClipRect()
.Rect()
.X());
EXPECT_EQ(PhysicalOffset(360, 10),
@@ -470,7 +479,7 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRLMulticol) {
EXPECT_EQ(460, FragmentAt(flow_thread, 1)
.PaintProperties()
->FragmentClip()
- ->ClipRect()
+ ->UnsnappedClipRect()
.Rect()
.MaxX());
EXPECT_EQ(PhysicalOffset(410, 210),
@@ -481,7 +490,7 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollVerticalRLMulticol) {
// Fragment geometries are not affected by parent scrolling.
ToLayoutBox(GetLayoutObjectByElementId("scroller"))
->GetScrollableArea()
- ->ScrollBy(ScrollOffset(-100, 200), kUserScroll);
+ ->ScrollBy(ScrollOffset(-100, 200), mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
check_fragments();
}
@@ -492,8 +501,7 @@ TEST_P(PaintPropertyTreeBuilderTest, DocScrollingTraditional) {
GetDocument().domWindow()->scrollTo(0, 100);
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_TRUE(DocPreTranslation()->IsIdentity());
EXPECT_EQ(
GetDocument().GetPage()->GetVisualViewport().GetScrollTranslationNode(),
@@ -501,7 +509,8 @@ TEST_P(PaintPropertyTreeBuilderTest, DocScrollingTraditional) {
EXPECT_EQ(FloatSize(0, -100), DocScrollTranslation()->Translation2D());
EXPECT_EQ(DocPreTranslation(), DocScrollTranslation()->Parent());
EXPECT_EQ(DocPreTranslation(), &DocContentClip()->LocalTransformSpace());
- EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), DocContentClip()->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600),
+ DocContentClip()->UnsnappedClipRect());
EXPECT_TRUE(DocContentClip()->Parent()->IsRoot());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(8, 8, 784, 10000),
@@ -1444,7 +1453,7 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGViewportContainer) {
ASSERT_NE(nullptr, clip);
EXPECT_EQ(nullptr, transform);
EXPECT_EQ(parent_clip, clip->Parent());
- EXPECT_EQ(FloatRect(0, 0, 30, 30), clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 30, 30), clip->UnsnappedClipRect().Rect());
EXPECT_EQ(parent_transform, &clip->LocalTransformSpace());
// overflow: hidden and non-zero offset and viewport scale:
@@ -1456,7 +1465,7 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGViewportContainer) {
ASSERT_NE(nullptr, clip);
ASSERT_NE(nullptr, transform);
EXPECT_EQ(parent_clip, clip->Parent());
- EXPECT_EQ(FloatRect(0, 0, 60, 60), clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 60, 60), clip->UnsnappedClipRect().Rect());
EXPECT_EQ(transform, &clip->LocalTransformSpace());
EXPECT_EQ(TransformationMatrix().Translate(40, 50).Scale(0.5),
transform->Matrix());
@@ -1499,7 +1508,7 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGForeignObjectOverflowClip) {
const auto* clip = properties1->OverflowClip();
ASSERT_NE(nullptr, clip);
EXPECT_EQ(parent_clip, clip->Parent());
- EXPECT_EQ(FloatRect(10, 20, 30, 40), clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(10, 20, 30, 40), clip->UnsnappedClipRect().Rect());
EXPECT_EQ(parent_transform, &clip->LocalTransformSpace());
const auto* properties2 = PaintPropertiesForElement("object2");
@@ -1523,7 +1532,7 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowClipWithEmptyVisualOverflow) {
const auto* clip = PaintPropertiesForElement("container")->OverflowClip();
EXPECT_NE(nullptr, clip);
- EXPECT_EQ(FloatRect(0, 0, 90, 90), clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 90, 90), clip->UnsnappedClipRect().Rect());
}
TEST_P(PaintPropertyTreeBuilderTest,
@@ -1615,7 +1624,7 @@ TEST_P(PaintPropertyTreeBuilderTest, ControlClip) {
&button_properties->OverflowClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(5, 5, 335, 113),
- button_properties->OverflowClip()->ClipRect());
+ button_properties->OverflowClip()->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(), button_properties->OverflowClip()->Parent());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(0, 0, 345, 123), &button,
GetDocument().View()->GetLayoutView());
@@ -1643,7 +1652,7 @@ TEST_P(PaintPropertyTreeBuilderTest, ControlClipInsideForeignObject) {
// not scroll (not enough content).
EXPECT_TRUE(DocScrollTranslation());
EXPECT_EQ(FloatRoundedRect(2, 2, 341, 119),
- button_properties->OverflowClip()->ClipRect());
+ button_properties->OverflowClip()->UnsnappedClipRect());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(8, 8, 345, 123), &button,
GetDocument().View()->GetLayoutView());
}
@@ -1682,7 +1691,7 @@ TEST_P(PaintPropertyTreeBuilderTest, BorderRadiusClip) {
// padding box = border box(500+60+50, 400+45+55) - border outset(60+50,
// 45+55) - scrollbars(15, 15)
EXPECT_EQ(FloatRoundedRect(60, 45, 500, 400),
- div_properties->OverflowClip()->ClipRect());
+ div_properties->OverflowClip()->UnsnappedClipRect());
const ClipPaintPropertyNode* border_radius_clip =
div_properties->OverflowClip()->Parent();
EXPECT_EQ(DocScrollTranslation(), &border_radius_clip->LocalTransformSpace());
@@ -1703,12 +1712,44 @@ TEST_P(PaintPropertyTreeBuilderTest, BorderRadiusClip) {
FloatSize(), // (top right) = max((34, 34) - (50, 45), (0, 0))
FloatSize(18, 23), // (bot left) = max((78, 78) - (60, 55), (0, 0))
FloatSize(6, 1)), // (bot right) = max((56, 56) - (50, 55), (0, 0))
- border_radius_clip->ClipRect());
+ border_radius_clip->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(), border_radius_clip->Parent());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(0, 0, 610, 500), &div,
GetDocument().View()->GetLayoutView());
}
+TEST_P(PaintPropertyTreeBuilderTest, SubpixelBorderRadiusClip) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0px;
+ }
+ #div {
+ margin-top: 0.5px;
+ width: 100px;
+ height: 100px;
+ overflow: hidden;
+ border-radius: 50%;
+ }
+ </style>
+ <div id='div'></div>
+ )HTML");
+
+ LayoutObject& div = *GetLayoutObjectByElementId("div");
+ const ObjectPaintProperties* div_properties =
+ div.FirstFragment().PaintProperties();
+
+ const ClipPaintPropertyNode* border_radius_clip =
+ div_properties->InnerBorderRadiusClip();
+ FloatSize corner(50, 50);
+ EXPECT_EQ(FloatRoundedRect(FloatRect(0, 0.5, 100, 100), corner, corner,
+ corner, corner),
+ border_radius_clip->UnsnappedClipRect());
+ EXPECT_EQ(FloatRoundedRect(FloatRect(0, 1, 100, 100), corner, corner, corner,
+ corner),
+ border_radius_clip->PixelSnappedClipRect());
+}
+
TEST_P(PaintPropertyTreeBuilderTest, TransformNodesAcrossSubframes) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -1734,8 +1775,7 @@ TEST_P(PaintPropertyTreeBuilderTest, TransformNodesAcrossSubframes) {
)HTML");
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
LayoutObject* div_with_transform =
GetLayoutObjectByElementId("divWithTransform");
@@ -1825,8 +1865,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FramesEstablishIsolation) {
)HTML");
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
LayoutObject* frame = ChildFrame().View()->GetLayoutView();
const auto& frame_contents_properties =
@@ -1884,8 +1923,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FramesEstablishIsolation) {
// However, isolation stops this recursion.
GetDocument().getElementById("parent")->setAttribute(html_names::kClassAttr,
"transformed");
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
// Verify that our clobbered state is still clobbered.
EXPECT_EQ(FloatSize(123, 321),
@@ -1922,8 +1960,7 @@ TEST_P(PaintPropertyTreeBuilderTest, TransformNodesInTransformedSubframes) {
<div id='transform'></div>
)HTML");
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
// Assert that we have the following tree structure:
// ...
@@ -2126,7 +2163,7 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipFixedPositionDescendant) {
EXPECT_EQ(DocScrollTranslation(),
&clip_properties->CssClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(FloatRect(absolute_clip_rect)),
- clip_properties->CssClip()->ClipRect());
+ clip_properties->CssClip()->UnsnappedClipRect());
CHECK_VISUAL_RECT(absolute_clip_rect, &clip,
GetDocument().View()->GetLayoutView(),
// TODO(crbug.com/599939): mapToVisualRectInAncestorSpace()
@@ -2186,7 +2223,7 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipAbsPositionDescendant) {
EXPECT_EQ(DocScrollTranslation(),
&clip_properties->CssClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(FloatRect(absolute_clip_rect)),
- clip_properties->CssClip()->ClipRect());
+ clip_properties->CssClip()->UnsnappedClipRect());
CHECK_VISUAL_RECT(absolute_clip_rect, clip,
GetDocument().View()->GetLayoutView(),
// TODO(crbug.com/599939): mapToVisualRectInAncestorSpace()
@@ -2228,7 +2265,8 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipSubpixel) {
PhysicalRect local_clip_rect(40, 10, 40, 60);
PhysicalRect absolute_clip_rect = local_clip_rect;
// Moved by 124 pixels due to pixel-snapping.
- absolute_clip_rect.offset += PhysicalOffset(124, 456);
+ absolute_clip_rect.offset +=
+ PhysicalOffset(LayoutSize(FloatSize(123.5, 456)));
auto* clip = GetLayoutObjectByElementId("clip");
const ObjectPaintProperties* clip_properties =
@@ -2240,7 +2278,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipSubpixel) {
EXPECT_EQ(DocScrollTranslation(),
&clip_properties->CssClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(FloatRect(absolute_clip_rect)),
- clip_properties->CssClip()->ClipRect());
+ clip_properties->CssClip()->UnsnappedClipRect());
+ EXPECT_EQ(FloatRoundedRect(PixelSnappedIntRect((absolute_clip_rect))),
+ clip_properties->CssClip()->PixelSnappedClipRect());
}
TEST_P(PaintPropertyTreeBuilderTest, CSSClipFixedPositionDescendantNonShared) {
@@ -2298,13 +2338,13 @@ TEST_P(PaintPropertyTreeBuilderTest, CSSClipFixedPositionDescendantNonShared) {
EXPECT_EQ(overflow_properties->ScrollTranslation(),
&clip_properties->CssClip()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(FloatRect(absolute_clip_rect)),
- clip_properties->CssClip()->ClipRect());
+ clip_properties->CssClip()->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(),
clip_properties->CssClipFixedPosition()->Parent());
EXPECT_EQ(overflow_properties->ScrollTranslation(),
&clip_properties->CssClipFixedPosition()->LocalTransformSpace());
EXPECT_EQ(FloatRoundedRect(FloatRect(absolute_clip_rect)),
- clip_properties->CssClipFixedPosition()->ClipRect());
+ clip_properties->CssClipFixedPosition()->UnsnappedClipRect());
CHECK_EXACT_VISUAL_RECT(PhysicalRect(), clip,
GetDocument().View()->GetLayoutView());
@@ -3411,9 +3451,10 @@ TEST_P(PaintPropertyTreeBuilderTest, ContainPaintOrStyleLayoutTreeState) {
&clipper->FirstFragment().LocalBorderBoxProperties().Clip());
// Clip isolation node should be big enough to encompass all other clips,
// including DocContentClip.
- EXPECT_TRUE(
- clip_properties->ClipIsolationNode()->ClipRect().Rect().Contains(
- DocContentClip()->ClipRect().Rect()));
+ EXPECT_TRUE(clip_properties->ClipIsolationNode()
+ ->UnsnappedClipRect()
+ .Rect()
+ .Contains(DocContentClip()->UnsnappedClipRect().Rect()));
// Verify contents properties and child properties:
@@ -3519,12 +3560,12 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowScrollWithRoundedRect) {
EXPECT_EQ(
FloatRoundedRect(FloatRect(50, 50, 200, 200), FloatSize(50, 50),
FloatSize(50, 50), FloatSize(50, 50), FloatSize(50, 50)),
- rounded_box_properties->InnerBorderRadiusClip()->ClipRect());
+ rounded_box_properties->InnerBorderRadiusClip()->UnsnappedClipRect());
// Unlike the inner border radius clip, the overflow clip is inset by the
// scrollbars (13px).
EXPECT_EQ(FloatRoundedRect(50, 50, 187, 187),
- rounded_box_properties->OverflowClip()->ClipRect());
+ rounded_box_properties->OverflowClip()->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(),
rounded_box_properties->InnerBorderRadiusClip()->Parent());
EXPECT_EQ(rounded_box_properties->InnerBorderRadiusClip(),
@@ -3920,7 +3961,7 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGRootClip) {
.PaintProperties()
->PaintOffsetTranslation()
->Translation2D());
- EXPECT_EQ(FloatRoundedRect(0, 0, 100, 100), clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 100, 100), clip->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeBuilderTest, SVGRootNoClip) {
@@ -3982,8 +4023,8 @@ TEST_P(PaintPropertyTreeBuilderTest, PaintOffsetsUnderMultiColumnScrolled) {
)HTML");
LayoutObject* scroller = GetLayoutObjectByElementId("scroller");
- ToLayoutBox(scroller)->GetScrollableArea()->ScrollBy(ScrollOffset(0, 300),
- kUserScroll);
+ ToLayoutBox(scroller)->GetScrollableArea()->ScrollBy(
+ ScrollOffset(0, 300), mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(FloatSize(8, 8), scroller->FirstFragment()
@@ -4072,8 +4113,8 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_EQ(PhysicalOffset(51, -20),
multicol_container->FirstFragment().NextFragment()->PaintOffset());
- GetDocument().View()->LayoutViewport()->ScrollBy(ScrollOffset(0, 25),
- kUserScroll);
+ GetDocument().View()->LayoutViewport()->ScrollBy(
+ ScrollOffset(0, 25), mojom::blink::ScrollType::kUser);
UpdateAllLifecyclePhasesForTest();
ASSERT_TRUE(multicol_container->FirstFragment().NextFragment());
@@ -4113,62 +4154,66 @@ TEST_P(PaintPropertyTreeBuilderTest, FragmentsUnderMultiColumn) {
EXPECT_EQ(4u, NumFragments(flowthread));
EXPECT_EQ(PhysicalOffset(), FragmentAt(relpos, 0).PaintOffset());
- EXPECT_EQ(PhysicalOffset(), FragmentAt(relpos, 0).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(), FragmentAt(relpos, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(), FragmentAt(relpos, 0).LogicalTopInFlowThread());
EXPECT_EQ(nullptr, FragmentAt(relpos, 0).PaintProperties());
EXPECT_EQ(PhysicalOffset(), FragmentAt(flowthread, 0).PaintOffset());
- EXPECT_EQ(PhysicalOffset(), FragmentAt(flowthread, 0).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(),
+ FragmentAt(flowthread, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(), FragmentAt(flowthread, 0).LogicalTopInFlowThread());
const auto* fragment_clip =
FragmentAt(flowthread, 0).PaintProperties()->FragmentClip();
ASSERT_NE(nullptr, fragment_clip);
EXPECT_EQ(FloatRect(-1000000, -1000000, 2000000, 1000030),
- fragment_clip->ClipRect().Rect());
+ fragment_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(fragment_clip,
&FragmentAt(relpos, 0).LocalBorderBoxProperties().Clip());
EXPECT_EQ(PhysicalOffset(100, -30), FragmentAt(relpos, 1).PaintOffset());
- EXPECT_EQ(PhysicalOffset(100, -30), FragmentAt(relpos, 1).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(100, -30),
+ FragmentAt(relpos, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(30), FragmentAt(relpos, 1).LogicalTopInFlowThread());
EXPECT_EQ(nullptr, FragmentAt(relpos, 1).PaintProperties());
EXPECT_EQ(PhysicalOffset(100, -30), FragmentAt(flowthread, 1).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -30),
- FragmentAt(flowthread, 1).PaginationOffset());
+ FragmentAt(flowthread, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(30), FragmentAt(flowthread, 1).LogicalTopInFlowThread());
fragment_clip = FragmentAt(flowthread, 1).PaintProperties()->FragmentClip();
ASSERT_NE(nullptr, fragment_clip);
EXPECT_EQ(FloatRect(-999900, 0, 2000000, 30),
- fragment_clip->ClipRect().Rect());
+ fragment_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(fragment_clip,
&FragmentAt(relpos, 1).LocalBorderBoxProperties().Clip());
EXPECT_EQ(PhysicalOffset(0, 20), FragmentAt(relpos, 2).PaintOffset());
- EXPECT_EQ(PhysicalOffset(0, 20), FragmentAt(relpos, 2).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(0, 20),
+ FragmentAt(relpos, 2).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(60), FragmentAt(relpos, 2).LogicalTopInFlowThread());
EXPECT_EQ(nullptr, FragmentAt(relpos, 2).PaintProperties());
EXPECT_EQ(PhysicalOffset(0, 20), FragmentAt(flowthread, 2).PaintOffset());
EXPECT_EQ(PhysicalOffset(0, 20),
- FragmentAt(flowthread, 2).PaginationOffset());
+ FragmentAt(flowthread, 2).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(60), FragmentAt(flowthread, 2).LogicalTopInFlowThread());
fragment_clip = FragmentAt(flowthread, 2).PaintProperties()->FragmentClip();
ASSERT_NE(nullptr, fragment_clip);
EXPECT_EQ(FloatRect(-1000000, 80, 2000000, 30),
- fragment_clip->ClipRect().Rect());
+ fragment_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(fragment_clip,
&FragmentAt(relpos, 2).LocalBorderBoxProperties().Clip());
EXPECT_EQ(PhysicalOffset(100, -10), FragmentAt(relpos, 3).PaintOffset());
- EXPECT_EQ(PhysicalOffset(100, -10), FragmentAt(relpos, 3).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(100, -10),
+ FragmentAt(relpos, 3).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(90), FragmentAt(relpos, 3).LogicalTopInFlowThread());
EXPECT_EQ(nullptr, FragmentAt(relpos, 3).PaintProperties());
EXPECT_EQ(PhysicalOffset(100, -10), FragmentAt(flowthread, 3).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -10),
- FragmentAt(flowthread, 3).PaginationOffset());
+ FragmentAt(flowthread, 3).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(90), FragmentAt(flowthread, 3).LogicalTopInFlowThread());
fragment_clip = FragmentAt(flowthread, 3).PaintProperties()->FragmentClip();
ASSERT_NE(nullptr, fragment_clip);
EXPECT_EQ(FloatRect(-999900, 80, 2000000, 999910),
- fragment_clip->ClipRect().Rect());
+ fragment_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(fragment_clip,
&FragmentAt(relpos, 3).LocalBorderBoxProperties().Clip());
@@ -4242,20 +4287,21 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_TRUE(thread->IsLayoutFlowThread());
EXPECT_EQ(2u, NumFragments(thread));
EXPECT_EQ(PhysicalOffset(100, 0), FragmentAt(thread, 0).PaintOffset());
- EXPECT_EQ(PhysicalOffset(), FragmentAt(thread, 0).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(), FragmentAt(thread, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(), FragmentAt(thread, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(300, 100), FragmentAt(thread, 1).PaintOffset());
- EXPECT_EQ(PhysicalOffset(200, 100), FragmentAt(thread, 1).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(200, 100),
+ FragmentAt(thread, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200), FragmentAt(thread, 1).LogicalTopInFlowThread());
LayoutObject* content = GetLayoutObjectByElementId("content");
EXPECT_EQ(2u, NumFragments(content));
EXPECT_EQ(PhysicalOffset(-200, 0), FragmentAt(content, 0).PaintOffset());
- EXPECT_EQ(PhysicalOffset(), FragmentAt(content, 0).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(), FragmentAt(content, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(), FragmentAt(content, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(0, 100), FragmentAt(content, 1).PaintOffset());
EXPECT_EQ(PhysicalOffset(200, 100),
- FragmentAt(content, 1).PaginationOffset());
+ FragmentAt(content, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200), FragmentAt(content, 1).LogicalTopInFlowThread());
}
@@ -4277,6 +4323,10 @@ TEST_P(PaintPropertyTreeBuilderTest, LayerUnderOverflowClipUnderMultiColumn) {
}
TEST_P(PaintPropertyTreeBuilderTest, CompositedUnderMultiColumn) {
+ // TODO(crbug.com/1064341): This test crashes in CompositeAfterPaint. Fix it.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; }</style>
<div id='multicol' style='columns:3; column-fill:auto; column-gap: 0;
@@ -4295,15 +4345,15 @@ TEST_P(PaintPropertyTreeBuilderTest, CompositedUnderMultiColumn) {
EXPECT_TRUE(thread->IsLayoutFlowThread());
EXPECT_EQ(3u, NumFragments(thread));
EXPECT_EQ(PhysicalOffset(), FragmentAt(thread, 0).PaintOffset());
- EXPECT_EQ(PhysicalOffset(), FragmentAt(thread, 0).PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(), FragmentAt(thread, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(), FragmentAt(thread, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(100, -200), FragmentAt(thread, 1).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -200),
- FragmentAt(thread, 1).PaginationOffset());
+ FragmentAt(thread, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200), FragmentAt(thread, 1).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(200, -400), FragmentAt(thread, 2).PaintOffset());
EXPECT_EQ(PhysicalOffset(200, -400),
- FragmentAt(thread, 2).PaginationOffset());
+ FragmentAt(thread, 2).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(400), FragmentAt(thread, 2).LogicalTopInFlowThread());
LayoutObject* composited = GetLayoutObjectByElementId("composited");
@@ -4317,33 +4367,33 @@ TEST_P(PaintPropertyTreeBuilderTest, CompositedUnderMultiColumn) {
EXPECT_EQ(PhysicalOffset(100, 100),
FragmentAt(composited, 0).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -200),
- FragmentAt(composited, 0).PaginationOffset());
+ FragmentAt(composited, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200),
FragmentAt(composited, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(200, -100),
FragmentAt(composited, 1).PaintOffset());
EXPECT_EQ(PhysicalOffset(200, -400),
- FragmentAt(composited, 1).PaginationOffset());
+ FragmentAt(composited, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(400),
FragmentAt(composited, 1).LogicalTopInFlowThread());
EXPECT_EQ(2u, NumFragments(non_composited_child));
EXPECT_EQ(PhysicalOffset(100, 100),
FragmentAt(non_composited_child, 0).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -200),
- FragmentAt(non_composited_child, 0).PaginationOffset());
+ FragmentAt(non_composited_child, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200),
FragmentAt(non_composited_child, 0).LogicalTopInFlowThread());
EXPECT_EQ(PhysicalOffset(200, -100),
FragmentAt(non_composited_child, 1).PaintOffset());
EXPECT_EQ(PhysicalOffset(200, -400),
- FragmentAt(non_composited_child, 1).PaginationOffset());
+ FragmentAt(non_composited_child, 1).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(400),
FragmentAt(non_composited_child, 1).LogicalTopInFlowThread());
EXPECT_EQ(1u, NumFragments(composited_child));
EXPECT_EQ(PhysicalOffset(200, 50),
FragmentAt(composited_child, 0).PaintOffset());
EXPECT_EQ(PhysicalOffset(200, -400),
- FragmentAt(composited_child, 0).PaginationOffset());
+ FragmentAt(composited_child, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(400),
FragmentAt(composited_child, 0).LogicalTopInFlowThread());
} else {
@@ -4352,21 +4402,21 @@ TEST_P(PaintPropertyTreeBuilderTest, CompositedUnderMultiColumn) {
EXPECT_EQ(PhysicalOffset(100, 100),
FragmentAt(composited, 0).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -200),
- FragmentAt(composited, 0).PaginationOffset());
+ FragmentAt(composited, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200),
FragmentAt(composited, 0).LogicalTopInFlowThread());
EXPECT_EQ(1u, NumFragments(non_composited_child));
EXPECT_EQ(PhysicalOffset(100, 100),
FragmentAt(non_composited_child, 0).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -200),
- FragmentAt(non_composited_child, 0).PaginationOffset());
+ FragmentAt(non_composited_child, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200),
FragmentAt(non_composited_child, 0).LogicalTopInFlowThread());
EXPECT_EQ(1u, NumFragments(composited_child));
EXPECT_EQ(PhysicalOffset(100, 250),
FragmentAt(composited_child, 0).PaintOffset());
EXPECT_EQ(PhysicalOffset(100, -200),
- FragmentAt(composited_child, 0).PaginationOffset());
+ FragmentAt(composited_child, 0).LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(200),
FragmentAt(composited_child, 0).LogicalTopInFlowThread());
}
@@ -4425,6 +4475,10 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameUnderMulticol) {
}
TEST_P(PaintPropertyTreeBuilderTest, CompositedMulticolFrameUnderMulticol) {
+ // TODO(crbug.com/1064341): This test crashes in CompositeAfterPaint. Fix it.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0 }</style>
<div style='columns: 3; column-gap: 0; column-fill: auto;
@@ -4448,8 +4502,9 @@ TEST_P(PaintPropertyTreeBuilderTest, CompositedMulticolFrameUnderMulticol) {
// TODO(crbug.com/797779): Add code to verify fragments under the iframe.
}
-TEST_P(PaintPropertyTreeBuilderTest,
- BecomingUnfragmentedClearsPaginationOffsetAndLogicalTopInFlowThread) {
+TEST_P(
+ PaintPropertyTreeBuilderTest,
+ BecomingUnfragmentedClearsLegacyPaginationOffsetAndLogicalTopInFlowThread) {
SetBodyInnerHTML(R"HTML(
<style>
#target {
@@ -4465,13 +4520,13 @@ TEST_P(PaintPropertyTreeBuilderTest,
LayoutObject* target = GetLayoutObjectByElementId("target");
EXPECT_EQ(PhysicalOffset(LayoutUnit(392.5f), LayoutUnit(-20)),
- target->FirstFragment().PaginationOffset());
+ target->FirstFragment().LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(20), target->FirstFragment().LogicalTopInFlowThread());
Element* target_element = GetDocument().getElementById("target");
target_element->setAttribute(html_names::kStyleAttr, "position: absolute");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(PhysicalOffset(), target->FirstFragment().PaginationOffset());
+ EXPECT_EQ(PhysicalOffset(), target->FirstFragment().LegacyPaginationOffset());
EXPECT_EQ(LayoutUnit(), target->FirstFragment().LogicalTopInFlowThread());
}
@@ -4740,8 +4795,10 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowClipSubpixelPosition) {
EXPECT_EQ(PhysicalOffset(LayoutUnit(31.5), LayoutUnit(20)),
clipper->FirstFragment().PaintOffset());
// Result is pixel-snapped.
+ EXPECT_EQ(FloatRect(31.5, 20, 400, 300),
+ clip_properties->OverflowClip()->UnsnappedClipRect().Rect());
EXPECT_EQ(FloatRect(32, 20, 400, 300),
- clip_properties->OverflowClip()->ClipRect().Rect());
+ clip_properties->OverflowClip()->PixelSnappedClipRect().Rect());
}
TEST_P(PaintPropertyTreeBuilderTest, MaskSimple) {
@@ -4759,7 +4816,7 @@ TEST_P(PaintPropertyTreeBuilderTest, MaskSimple) {
EXPECT_EQ(output_clip,
&target->FirstFragment().LocalBorderBoxProperties().Clip());
EXPECT_EQ(DocContentClip(), output_clip->Parent());
- EXPECT_EQ(FloatRoundedRect(8, 8, 300, 200), output_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 300, 200), output_clip->UnsnappedClipRect());
EXPECT_EQ(properties->Effect(),
&target->FirstFragment().LocalBorderBoxProperties().Effect());
@@ -4788,7 +4845,8 @@ TEST_P(PaintPropertyTreeBuilderTest, MaskWithOutset) {
EXPECT_EQ(output_clip,
&target->FirstFragment().LocalBorderBoxProperties().Clip());
EXPECT_EQ(DocContentClip(), output_clip->Parent());
- EXPECT_EQ(FloatRoundedRect(-12, -2, 340, 220), output_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(-12, -2, 340, 220),
+ output_clip->UnsnappedClipRect());
EXPECT_EQ(properties->Effect(),
&target->FirstFragment().LocalBorderBoxProperties().Effect());
@@ -4831,18 +4889,20 @@ TEST_P(PaintPropertyTreeBuilderTest, MaskEscapeClip) {
PaintPropertiesForElement("scroll");
EXPECT_EQ(DocContentClip(), overflow_clip1->Parent());
- EXPECT_EQ(FloatRoundedRect(0, 0, 300, 200), overflow_clip1->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 300, 200),
+ overflow_clip1->UnsnappedClipRect());
EXPECT_EQ(scroll_properties->PaintOffsetTranslation(),
&overflow_clip1->LocalTransformSpace());
EXPECT_EQ(mask_clip,
&target->FirstFragment().LocalBorderBoxProperties().Clip());
EXPECT_EQ(overflow_clip1, mask_clip->Parent());
- EXPECT_EQ(FloatRoundedRect(0, 0, 220, 320), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 220, 320), mask_clip->UnsnappedClipRect());
EXPECT_EQ(&scroll_translation, &mask_clip->LocalTransformSpace());
EXPECT_EQ(mask_clip, overflow_clip2->Parent());
- EXPECT_EQ(FloatRoundedRect(10, 10, 200, 300), overflow_clip2->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(10, 10, 200, 300),
+ overflow_clip2->UnsnappedClipRect());
EXPECT_EQ(&scroll_translation, &overflow_clip2->LocalTransformSpace());
EXPECT_EQ(target_properties->Effect(),
@@ -4894,7 +4954,8 @@ TEST_P(PaintPropertyTreeBuilderTest, MaskInline) {
EXPECT_EQ(output_clip,
&target->FirstFragment().LocalBorderBoxProperties().Clip());
EXPECT_EQ(DocContentClip(), output_clip->Parent());
- EXPECT_EQ(FloatRoundedRect(104, 21, 432, 16), output_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(104, 21, 432, 16),
+ output_clip->UnsnappedClipRect());
EXPECT_EQ(properties->Effect(),
&target->FirstFragment().LocalBorderBoxProperties().Effect());
@@ -5097,16 +5158,10 @@ TEST_P(PaintPropertyTreeBuilderTest, BackfaceHidden) {
ASSERT_NE(nullptr, target_properties);
const auto* paint_offset_translation =
target_properties->PaintOffsetTranslation();
- if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- EXPECT_EQ(nullptr, paint_offset_translation);
- EXPECT_EQ(PhysicalOffset(60, 50), target->FirstFragment().PaintOffset());
- } else {
- // For SPv1, |target| is composited so we created PaintOffsetTranslation.
- ASSERT_NE(nullptr, paint_offset_translation);
- EXPECT_EQ(FloatSize(60, 50), paint_offset_translation->Translation2D());
- EXPECT_EQ(TransformPaintPropertyNode::BackfaceVisibility::kInherited,
- paint_offset_translation->GetBackfaceVisibilityForTesting());
- }
+ ASSERT_NE(nullptr, paint_offset_translation);
+ EXPECT_EQ(FloatSize(60, 50), paint_offset_translation->Translation2D());
+ EXPECT_EQ(TransformPaintPropertyNode::BackfaceVisibility::kInherited,
+ paint_offset_translation->GetBackfaceVisibilityForTesting());
const auto* transform = target_properties->Transform();
ASSERT_NE(nullptr, transform);
@@ -5140,7 +5195,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameBorderRadius) {
FloatSize radius(30, 30);
EXPECT_EQ(FloatRoundedRect(FloatRect(28, 28, 200, 200), radius, radius,
radius, radius),
- border_radius_clip->ClipRect());
+ border_radius_clip->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(), border_radius_clip->Parent());
EXPECT_EQ(DocScrollTranslation(), &border_radius_clip->LocalTransformSpace());
EXPECT_EQ(nullptr, properties->InnerBorderRadiusClip());
@@ -5167,7 +5222,7 @@ TEST_P(PaintPropertyTreeBuilderTest, ImageBorderRadius) {
FloatSize radius(20, 20);
EXPECT_EQ(FloatRoundedRect(FloatRect(18, 18, 50, 50), radius, radius, radius,
radius),
- border_radius_clip->ClipRect());
+ border_radius_clip->UnsnappedClipRect());
EXPECT_EQ(DocContentClip(), border_radius_clip->Parent());
EXPECT_EQ(DocScrollTranslation(), &border_radius_clip->LocalTransformSpace());
EXPECT_EQ(nullptr, properties->InnerBorderRadiusClip());
@@ -5183,10 +5238,10 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameClipWhenPrinting) {
auto* const child_frame_doc = &ChildDocument();
ASSERT_NE(nullptr, DocContentClip(main_frame_doc));
EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
- DocContentClip(main_frame_doc)->ClipRect().Rect());
+ DocContentClip(main_frame_doc)->UnsnappedClipRect().Rect());
ASSERT_NE(nullptr, DocContentClip(child_frame_doc));
EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
- DocContentClip(child_frame_doc)->ClipRect().Rect());
+ DocContentClip(child_frame_doc)->UnsnappedClipRect().Rect());
// When the main frame is printing, it should not have content clip.
FloatSize page_size(100, 100);
@@ -5195,7 +5250,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameClipWhenPrinting) {
EXPECT_EQ(nullptr, DocContentClip(main_frame_doc));
ASSERT_NE(nullptr, DocContentClip(child_frame_doc));
EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
- DocContentClip(child_frame_doc)->ClipRect().Rect());
+ DocContentClip(child_frame_doc)->UnsnappedClipRect().Rect());
GetFrame().EndPrinting();
UpdateAllLifecyclePhasesForTest();
@@ -5206,7 +5261,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameClipWhenPrinting) {
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
ASSERT_NE(nullptr, DocContentClip(main_frame_doc));
EXPECT_NE(FloatRect(LayoutRect::InfiniteIntRect()),
- DocContentClip(main_frame_doc)->ClipRect().Rect());
+ DocContentClip(main_frame_doc)->UnsnappedClipRect().Rect());
EXPECT_EQ(nullptr, DocContentClip(child_frame_doc));
}
@@ -5220,7 +5275,8 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowControlsClip) {
const auto* properties1 = PaintPropertiesForElement("div1");
ASSERT_NE(nullptr, properties1);
const auto* overflow_controls_clip = properties1->OverflowControlsClip();
- EXPECT_EQ(FloatRect(0, 0, 5, 50), overflow_controls_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 5, 50),
+ overflow_controls_clip->UnsnappedClipRect().Rect());
const auto* properties2 = PaintPropertiesForElement("div2");
ASSERT_NE(nullptr, properties2);
@@ -5237,7 +5293,10 @@ TEST_P(PaintPropertyTreeBuilderTest, OverflowControlsClipSubpixel) {
const auto* properties1 = PaintPropertiesForElement("div1");
ASSERT_NE(nullptr, properties1);
const auto* overflow_controls_clip = properties1->OverflowControlsClip();
- EXPECT_EQ(FloatRect(0, 0, 6, 50), overflow_controls_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 5.5, 50),
+ overflow_controls_clip->UnsnappedClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 6, 50),
+ overflow_controls_clip->PixelSnappedClipRect().Rect());
const auto* properties2 = PaintPropertiesForElement("div2");
ASSERT_NE(nullptr, properties2);
@@ -5289,9 +5348,10 @@ TEST_P(PaintPropertyTreeBuilderTest, FragmentClipPixelSnapped) {
FragmentAt(flow_thread, 1).PaintProperties()->FragmentClip();
EXPECT_EQ(FloatRect(-999992, -999992, 2000000, 1000050),
- first_clip->ClipRect().Rect());
+ first_clip->PixelSnappedClipRect().Rect());
+
EXPECT_EQ(FloatRect(-999967, 8, 2000000, 999951),
- second_clip->ClipRect().Rect());
+ second_clip->PixelSnappedClipRect().Rect());
}
TEST_P(PaintPropertyTreeBuilderTest,
@@ -5310,18 +5370,11 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_FALSE(ToLayoutBoxModelObject(target)->Layer()->SelfNeedsRepaint());
opacity_element->setAttribute(html_names::kStyleAttr, "opacity: 0.5");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
- if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
- // TODO(crbug.com/900241): Without CompositeAfterPaint, we create effect and
- // filter nodes when the transform node needs compositing for
- // will-change:transform, for crbug.com/942681.
- EXPECT_FALSE(ToLayoutBoxModelObject(target)->Layer()->SelfNeedsRepaint());
- } else {
- // All paint chunks contained by the new opacity effect node need to be
- // re-painted.
- EXPECT_TRUE(ToLayoutBoxModelObject(target)->Layer()->SelfNeedsRepaint());
- }
+ EXPECT_TRUE(opacity_element->GetLayoutBox()->Layer()->SelfNeedsRepaint());
+ EXPECT_FALSE(ToLayoutBoxModelObject(target)->Layer()->SelfNeedsRepaint());
}
TEST_P(PaintPropertyTreeBuilderTest, SVGRootWithMask) {
@@ -5374,7 +5427,8 @@ TEST_P(PaintPropertyTreeBuilderTest, ClearClipPathEffectNode) {
Element* clip = GetDocument().getElementById("clip");
ASSERT_TRUE(clip);
clip->remove();
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
{
const auto* rect = GetLayoutObjectByElementId("rect");
@@ -5395,7 +5449,8 @@ TEST_P(PaintPropertyTreeBuilderTest, RootHasCompositedScrolling) {
// Remove scrolling from the root.
Element* force_scroll_element = GetDocument().getElementById("forceScroll");
force_scroll_element->setAttribute(html_names::kStyleAttr, "");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Always create scroll translation for layout view even the document does
// not scroll (not enough content).
EXPECT_TRUE(DocScrollTranslation());
@@ -5505,7 +5560,8 @@ TEST_P(PaintPropertyTreeBuilderTest, ClipHitTestChangeDoesNotCauseFullRepaint) {
EXPECT_FALSE(child_layer->SelfNeedsRepaint());
GetDocument().body()->setAttribute(html_names::kClassAttr, "noscrollbars");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(child_layer->SelfNeedsRepaint());
}
@@ -5570,7 +5626,11 @@ TEST_P(PaintPropertyTreeBuilderTest, CompositedLayerSkipsFragmentClip) {
.Clip());
}
-TEST_P(PaintPropertyTreeBuilderTest, CompositedLayerUnderClipUnerMulticol) {
+TEST_P(PaintPropertyTreeBuilderTest, CompositedLayerUnderClipUnderMulticol) {
+ // TODO(crbug.com/1064341): This test crashes in CompositeAfterPaint. Fix it.
+ if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ return;
+
SetBodyInnerHTML(R"HTML(
<div id="multicol" style="columns: 2">
<div id="clip" style="height: 100px; overflow: hidden">
@@ -6024,26 +6084,6 @@ TEST_P(PaintPropertyTreeBuilderTest, StickyConstraintChain) {
->nearest_element_shifting_containing_block);
}
-TEST_P(PaintPropertyTreeBuilderTest, RoundedStickyConstraints) {
- // This test verifies that sticky constraint rects are rounded to the nearest
- // integer.
- SetBodyInnerHTML(R"HTML(
- <div id="scroller" style="overflow:scroll; width:300px; height:199.5px;">
- <div id="outer" style="position:sticky; top:10px; height:300px">
- </div>
- <div style="height:1000px;"></div>
- </div>
- )HTML");
- GetDocument().getElementById("scroller")->setScrollTop(50);
- UpdateAllLifecyclePhasesForTest();
-
- const auto* outer_properties = PaintPropertiesForElement("outer");
- ASSERT_TRUE(outer_properties && outer_properties->StickyTranslation());
- EXPECT_EQ(gfx::Rect(0, 0, 300, 200), outer_properties->StickyTranslation()
- ->GetStickyConstraint()
- ->constraint_box_rect);
-}
-
TEST_P(PaintPropertyTreeBuilderTest, NonScrollableSticky) {
// This test verifies the property tree builder applies sticky offset
// correctly when the clipping container cannot be scrolled, and
@@ -6098,7 +6138,8 @@ TEST_P(PaintPropertyTreeBuilderTest, WillChangeOpacityInducesAnEffectNode) {
auto* div = GetDocument().getElementById("div");
div->setAttribute(html_names::kClassAttr, "transluscent");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(
ToLayoutBox(div->GetLayoutObject())->Layer()->SelfNeedsRepaint());
@@ -6208,39 +6249,49 @@ TEST_P(PaintPropertyTreeBuilderTest, SVGRootCompositedClipPath) {
const auto* clip_path_clip = properties->ClipPathClip();
ASSERT_NE(nullptr, clip_path_clip);
EXPECT_EQ(DocContentClip(), clip_path_clip->Parent());
- EXPECT_EQ(FloatRect(75, 0, 150, 150), clip_path_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(75, 0, 150, 150),
+ clip_path_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(transform, &clip_path_clip->LocalTransformSpace());
EXPECT_NE(nullptr, clip_path_clip->ClipPath());
const auto* overflow_clip = properties->OverflowClip();
ASSERT_NE(nullptr, overflow_clip);
EXPECT_EQ(clip_path_clip, overflow_clip->Parent());
- EXPECT_EQ(FloatRect(0, 0, 300, 150), overflow_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 300, 150),
+ overflow_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(transform, &overflow_clip->LocalTransformSpace());
- // TODO(wangxianzhu): Are the following correct?
- EXPECT_EQ(nullptr, properties->Effect());
+ const auto* effect = properties->Effect();
+ ASSERT_NE(nullptr, effect);
+ EXPECT_EQ(&EffectPaintPropertyNode::Root(), effect->Parent());
+ EXPECT_EQ(transform, &effect->LocalTransformSpace());
+ EXPECT_EQ(clip_path_clip, effect->OutputClip());
+ EXPECT_EQ(SkBlendMode::kSrcOver, effect->BlendMode());
+
EXPECT_EQ(nullptr, properties->Mask());
EXPECT_EQ(nullptr, properties->ClipPath());
} else {
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
EXPECT_EQ(DocContentClip(), mask_clip->Parent());
- EXPECT_EQ(FloatRect(75, 0, 150, 150), mask_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(75, 0, 150, 150),
+ mask_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(nullptr, mask_clip->ClipPath());
EXPECT_EQ(transform, &mask_clip->LocalTransformSpace());
const auto* clip_path_clip = properties->ClipPathClip();
ASSERT_NE(nullptr, clip_path_clip);
EXPECT_EQ(mask_clip, clip_path_clip->Parent());
- EXPECT_EQ(FloatRect(75, 0, 150, 150), clip_path_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(75, 0, 150, 150),
+ clip_path_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(transform, &clip_path_clip->LocalTransformSpace());
EXPECT_NE(nullptr, clip_path_clip->ClipPath());
const auto* overflow_clip = properties->OverflowClip();
ASSERT_NE(nullptr, overflow_clip);
EXPECT_EQ(mask_clip, overflow_clip->Parent());
- EXPECT_EQ(FloatRect(0, 0, 300, 150), overflow_clip->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 300, 150),
+ overflow_clip->UnsnappedClipRect().Rect());
EXPECT_EQ(transform, &overflow_clip->LocalTransformSpace());
const auto* effect = properties->Effect();
@@ -6305,7 +6356,8 @@ TEST_P(PaintPropertyTreeBuilderTest, SimpleOpacityChangeDoesNotCausePacUpdate) {
Element* element = GetDocument().getElementById("element");
element->setAttribute(html_names::kStyleAttr, "opacity: 0.9");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FLOAT_EQ(properties->Effect()->Opacity(), 0.9f);
EXPECT_FLOAT_EQ(cc_effect->opacity, 0.9f);
EXPECT_TRUE(cc_effect->effect_changed);
@@ -6369,7 +6421,8 @@ TEST_P(PaintPropertyTreeBuilderTest, SimpleScrollChangeDoesNotCausePacUpdate) {
EXPECT_FLOAT_EQ(current_scroll_offset.y(), 0);
GetDocument().getElementById("element")->setScrollTop(10.);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FLOAT_SIZE_EQ(FloatSize(0, -10),
properties->ScrollTranslation()->Translation2D());
@@ -6381,7 +6434,6 @@ TEST_P(PaintPropertyTreeBuilderTest, SimpleScrollChangeDoesNotCausePacUpdate) {
properties->ScrollTranslation()->ScrollNode()->GetCompositorElementId());
EXPECT_FLOAT_EQ(current_scroll_offset.x(), 0);
EXPECT_FLOAT_EQ(current_scroll_offset.y(), 10);
- EXPECT_TRUE(property_trees->scroll_tree.needs_update());
EXPECT_TRUE(property_trees->transform_tree.needs_update());
EXPECT_TRUE(cc_transform_node->transform_changed);
@@ -6413,7 +6465,8 @@ TEST_P(PaintPropertyTreeBuilderTest,
Element* outer = GetDocument().getElementById("outer");
outer->setAttribute(html_names::kStyleAttr, "transform: translateY(10px)");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(
GetDocument().View()->GetPaintArtifactCompositor()->NeedsUpdate());
@@ -6464,24 +6517,22 @@ TEST_P(PaintPropertyTreeBuilderTest, VideoClipRect) {
video_element->SetInlineStyleProperty(CSSPropertyID::kTop, "0.1px");
video_element->SetInlineStyleProperty(CSSPropertyID::kLeft, "0.1px");
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
const ObjectPaintProperties* video_element_properties =
video_element->GetLayoutObject()->FirstFragment().PaintProperties();
// |video_element| is now sub-pixel positioned, at 0.1,0.1 320.2x240. With or
// without pixel-snapped clipping, this will get clipped at 0,0 320x240.
EXPECT_EQ(FloatRoundedRect(0, 0, 320, 240),
- video_element_properties->OverflowClip()->ClipRect());
+ video_element_properties->OverflowClip()->UnsnappedClipRect());
// Now, move |video_element| to 10.4,10.4. At this point, without pixel
// snapping that doesn't depend on paint offset, it will be clipped at 10,10
// 321x240. With proper pixel snapping, the clip will be at 10,10,320,240.
video_element->SetInlineStyleProperty(CSSPropertyID::kTop, "10.4px");
video_element->SetInlineStyleProperty(CSSPropertyID::kLeft, "10.4px");
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_EQ(FloatRoundedRect(10, 10, 320, 240),
- video_element_properties->OverflowClip()->ClipRect());
+ video_element_properties->OverflowClip()->UnsnappedClipRect());
}
// For NoPaintPropertyForXXXText cases. The styles trigger almost all paint
@@ -6529,65 +6580,6 @@ TEST_P(PaintPropertyTreeBuilderTest, NoPaintPropertyForSVGText) {
EXPECT_FALSE(text->FirstFragment().PaintProperties());
}
-TEST_P(PaintPropertyTreeBuilderTest, SetViewportScrollingBits) {
- SetBodyInnerHTML(R"HTML(
- <style>
- body, html {
- margin: 0;
- width: 100%;
- height: 100%;
- }
- #scroller {
- width: 100%;
- height: 200%;
- overflow: auto;
- }
- </style>
- <div id="scroller">
- <div style="height: 3000px"></div>
- </div>
- )HTML");
-
- const auto* scroller_node = PaintPropertiesForElement("scroller")->Scroll();
- const auto* document_node = DocScroll();
-
- // Ensure the LayoutView's ScrollNode is marked as scrolling the "outer" or
- // "layout" viewport.
- {
- EXPECT_FALSE(scroller_node->ScrollsOuterViewport());
- EXPECT_TRUE(document_node->ScrollsOuterViewport());
- }
-
- // Ensure the visual viewport is the only one that sets the inner scroll bit.
- {
- EXPECT_TRUE(GetDocument()
- .GetPage()
- ->GetVisualViewport()
- .GetScrollNode()
- ->ScrollsInnerViewport());
- EXPECT_FALSE(scroller_node->ScrollsInnerViewport());
- EXPECT_FALSE(document_node->ScrollsInnerViewport());
- }
-
- // Make the scroller fill the viewport. This will make it eligible for root
- // scroller promotion. Ensure the outer viewport scrolling property is
- // correctly recomputed, moving it from the LayoutView to the scroller.
- {
- Element* scroller = GetDocument().getElementById("scroller");
- scroller->setAttribute(html_names::kStyleAttr, "height: 100%");
- LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
- ASSERT_TRUE(scroller->GetLayoutObject()->IsGlobalRootScroller());
-
- EXPECT_TRUE(scroller_node->ScrollsOuterViewport());
-
- // Since the document is no longer scrollable and isn't the root scroller
- // it shouldn't have a node.
- EXPECT_FALSE(DocScroll());
- }
-}
-
TEST_P(PaintPropertyTreeBuilderTest, IsAffectedByOuterViewportBoundsDelta) {
SetBodyInnerHTML(R"HTML(
<style>div { will-change: transform; position: fixed; }</style>
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
index 057f90eb7a5..59a6b43f841 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
@@ -54,7 +54,7 @@ class FrameViewPropertyTreePrinter
for (const auto* fragment = &object.FirstFragment(); fragment;
fragment = fragment->NextFragment()) {
if (const auto* properties = fragment->PaintProperties())
- Traits::AddObjectPaintProperties(object, *properties, *this);
+ Traits::AddObjectPaintProperties(*properties, *this);
}
for (const auto* child = object.SlowFirstChild(); child;
child = child->NextSibling()) {
@@ -75,7 +75,6 @@ class PropertyTreePrinterTraits<TransformPaintPropertyNode> {
printer.AddNode(visual_viewport.GetScrollTranslationNode());
}
static void AddObjectPaintProperties(
- const LayoutObject& object,
const ObjectPaintProperties& properties,
PropertyTreePrinter<TransformPaintPropertyNode>& printer) {
printer.AddNode(properties.PaintOffsetTranslation());
@@ -95,7 +94,6 @@ class PropertyTreePrinterTraits<ClipPaintPropertyNode> {
const VisualViewport& visual_viewport,
PropertyTreePrinter<ClipPaintPropertyNode>& printer) {}
static void AddObjectPaintProperties(
- const LayoutObject& object,
const ObjectPaintProperties& properties,
PropertyTreePrinter<ClipPaintPropertyNode>& printer) {
printer.AddNode(properties.FragmentClip());
@@ -118,7 +116,6 @@ class PropertyTreePrinterTraits<EffectPaintPropertyNode> {
PropertyTreePrinter<EffectPaintPropertyNode>& printer) {}
static void AddObjectPaintProperties(
- const LayoutObject& object,
const ObjectPaintProperties& properties,
PropertyTreePrinter<EffectPaintPropertyNode>& printer) {
printer.AddNode(properties.Effect());
@@ -141,7 +138,6 @@ class PropertyTreePrinterTraits<ScrollPaintPropertyNode> {
}
static void AddObjectPaintProperties(
- const LayoutObject& object,
const ObjectPaintProperties& properties,
PropertyTreePrinter<ScrollPaintPropertyNode>& printer) {
printer.AddNode(properties.Scroll());
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index da6c4c0a9bf..8f6de40bed2 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -315,8 +315,7 @@ TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
"translate3d(4px, 5px, 6px); width: 100px; height: 200px'></div>");
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
LayoutObject* div_with_transform =
GetLayoutObjectByElementId("divWithTransform");
@@ -342,8 +341,7 @@ TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
EXPECT_FALSE(inner_div_with_transform->DescendantNeedsPaintPropertyUpdate());
// After a lifecycle update, no nodes should need a descendant update.
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_FALSE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
EXPECT_FALSE(div_with_transform->DescendantNeedsPaintPropertyUpdate());
@@ -356,8 +354,7 @@ TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
child_frame_view->SetNeedsPaintPropertyUpdate();
EXPECT_TRUE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_FALSE(
GetDocument().GetLayoutView()->DescendantNeedsPaintPropertyUpdate());
EXPECT_FALSE(GetDocument().GetLayoutView()->NeedsPaintPropertyUpdate());
@@ -368,16 +365,20 @@ TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
TEST_P(PaintPropertyTreeUpdateTest, UpdatingFrameViewContentClip) {
SetBodyInnerHTML("hello world.");
- EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), DocContentClip()->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600),
+ DocContentClip()->UnsnappedClipRect());
GetDocument().View()->Resize(800, 599);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599), DocContentClip()->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599),
+ DocContentClip()->UnsnappedClipRect());
GetDocument().View()->Resize(800, 600);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), DocContentClip()->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600),
+ DocContentClip()->UnsnappedClipRect());
GetDocument().View()->Resize(5, 5);
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5), DocContentClip()->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5),
+ DocContentClip()->UnsnappedClipRect());
}
// There is also FrameThrottlingTest.UpdatePaintPropertiesOnUnthrottling
@@ -477,17 +478,17 @@ TEST_P(PaintPropertyTreeUpdateTest, ClipChangesUpdateOverflowClip) {
UpdateAllLifecyclePhasesForTest();
auto* clip_properties =
div->GetLayoutObject()->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatRect(0, 0, 7, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 7, 0), clip_properties->UnsnappedClipRect().Rect());
// Width changes should update the overflow clip.
div->setAttribute(html_names::kStyleAttr, "display:inline-block; width:7px;");
UpdateAllLifecyclePhasesForTest();
clip_properties =
div->GetLayoutObject()->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatRect(0, 0, 7, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 7, 0), clip_properties->UnsnappedClipRect().Rect());
div->setAttribute(html_names::kStyleAttr, "display:inline-block; width:9px;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRect(0, 0, 9, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 9, 0), clip_properties->UnsnappedClipRect().Rect());
// An inline block's overflow clip should be updated when padding changes,
// even if the border box remains unchanged.
@@ -496,33 +497,39 @@ TEST_P(PaintPropertyTreeUpdateTest, ClipChangesUpdateOverflowClip) {
UpdateAllLifecyclePhasesForTest();
clip_properties =
div->GetLayoutObject()->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatRect(0, 0, 10, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 10, 0),
+ clip_properties->UnsnappedClipRect().Rect());
div->setAttribute(html_names::kStyleAttr,
"display:inline-block; width:8px; padding-right:2px;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRect(0, 0, 10, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 10, 0),
+ clip_properties->UnsnappedClipRect().Rect());
div->setAttribute(html_names::kStyleAttr,
"display:inline-block; width:8px;"
"padding-right:1px; padding-left:1px;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRect(0, 0, 10, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 10, 0),
+ clip_properties->UnsnappedClipRect().Rect());
// An block's overflow clip should be updated when borders change.
div->setAttribute(html_names::kStyleAttr, "border-right:3px solid red;");
UpdateAllLifecyclePhasesForTest();
clip_properties =
div->GetLayoutObject()->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatRect(0, 0, 797, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 797, 0),
+ clip_properties->UnsnappedClipRect().Rect());
div->setAttribute(html_names::kStyleAttr, "border-right:5px solid red;");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(FloatRect(0, 0, 795, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 795, 0),
+ clip_properties->UnsnappedClipRect().Rect());
// Removing overflow clip should remove the property.
div->setAttribute(html_names::kStyleAttr, "overflow:hidden;");
UpdateAllLifecyclePhasesForTest();
clip_properties =
div->GetLayoutObject()->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatRect(0, 0, 800, 0), clip_properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 800, 0),
+ clip_properties->UnsnappedClipRect().Rect());
div->setAttribute(html_names::kStyleAttr, "overflow:visible;");
UpdateAllLifecyclePhasesForTest();
EXPECT_TRUE(!div->GetLayoutObject()->FirstFragment().PaintProperties() ||
@@ -546,7 +553,7 @@ TEST_P(PaintPropertyTreeUpdateTest, ContainPaintChangesUpdateOverflowClip) {
auto* div = GetDocument().getElementById("div");
auto* properties =
div->GetLayoutObject()->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->UnsnappedClipRect().Rect());
div->setAttribute(html_names::kStyleAttr, "");
UpdateAllLifecyclePhasesForTest();
@@ -564,7 +571,8 @@ TEST_P(PaintPropertyTreeUpdateTest, NoPaintPropertyUpdateOnBackgroundChange) {
UpdateAllLifecyclePhasesForTest();
div->setAttribute(html_names::kStyleAttr, "background-color: green");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(div->GetLayoutObject()->NeedsPaintPropertyUpdate());
}
@@ -582,16 +590,14 @@ TEST_P(PaintPropertyTreeUpdateTest,
"<div id='forceScroll' style='height: 3000px;'></div>");
LocalFrameView* frame_view = GetDocument().View();
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_EQ(nullptr, DocScroll());
Document* child_doc = &ChildDocument();
EXPECT_NE(nullptr, DocScroll(child_doc));
auto* iframe_container = GetDocument().getElementById("iframeContainer");
iframe_container->setAttribute(html_names::kStyleAttr, "visibility: hidden;");
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_EQ(nullptr, DocScroll());
EXPECT_EQ(nullptr, DocScroll(child_doc));
@@ -760,15 +766,19 @@ TEST_P(PaintPropertyTreeUpdateTest, CSSClipDependingOnSize) {
auto* outer = GetDocument().getElementById("outer");
auto* clip = GetLayoutObjectByElementId("clip");
- EXPECT_EQ(
- FloatRect(45, 50, 105, 100),
- clip->FirstFragment().PaintProperties()->CssClip()->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(45, 50, 105, 100), clip->FirstFragment()
+ .PaintProperties()
+ ->CssClip()
+ ->UnsnappedClipRect()
+ .Rect());
outer->setAttribute(html_names::kStyleAttr, "height: 200px");
UpdateAllLifecyclePhasesForTest();
- EXPECT_EQ(
- FloatRect(45, 50, 105, 200),
- clip->FirstFragment().PaintProperties()->CssClip()->ClipRect().Rect());
+ EXPECT_EQ(FloatRect(45, 50, 105, 200), clip->FirstFragment()
+ .PaintProperties()
+ ->CssClip()
+ ->UnsnappedClipRect()
+ .Rect());
}
TEST_P(PaintPropertyTreeUpdateTest, ScrollBoundsChange) {
@@ -888,7 +898,8 @@ TEST_P(PaintPropertyTreeUpdateTest, ScrollbarWidthChange) {
auto* container = GetLayoutObjectByElementId("container");
auto* overflow_clip =
container->FirstFragment().PaintProperties()->OverflowClip();
- EXPECT_EQ(FloatSize(80, 80), overflow_clip->ClipRect().Rect().Size());
+ EXPECT_EQ(FloatSize(80, 80),
+ overflow_clip->UnsnappedClipRect().Rect().Size());
auto* new_style = GetDocument().CreateRawElement(html_names::kStyleTag);
new_style->setTextContent("::-webkit-scrollbar {width: 40px; height: 40px}");
@@ -897,7 +908,8 @@ TEST_P(PaintPropertyTreeUpdateTest, ScrollbarWidthChange) {
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(overflow_clip,
container->FirstFragment().PaintProperties()->OverflowClip());
- EXPECT_EQ(FloatSize(60, 60), overflow_clip->ClipRect().Rect().Size());
+ EXPECT_EQ(FloatSize(60, 60),
+ overflow_clip->UnsnappedClipRect().Rect().Size());
}
TEST_P(PaintPropertyTreeUpdateTest, Preserve3DChange) {
@@ -956,7 +968,7 @@ TEST_P(PaintPropertyTreeUpdateTest, BoxAddRemoveMask) {
EXPECT_NE(nullptr, properties->Mask());
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
- EXPECT_EQ(FloatRoundedRect(8, 8, 100, 100), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 100, 100), mask_clip->UnsnappedClipRect());
target->setAttribute(html_names::kStyleAttr, "");
UpdateAllLifecyclePhasesForTest();
@@ -981,14 +993,14 @@ TEST_P(PaintPropertyTreeUpdateTest, MaskClipNodeBoxSizeChange) {
ASSERT_NE(nullptr, properties);
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
- EXPECT_EQ(FloatRoundedRect(8, 8, 100, 100), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 100, 100), mask_clip->UnsnappedClipRect());
GetDocument().getElementById("target")->setAttribute(html_names::kStyleAttr,
"height: 200px");
UpdateAllLifecyclePhasesForTest();
ASSERT_EQ(mask_clip, properties->MaskClip());
- EXPECT_EQ(FloatRoundedRect(8, 8, 100, 200), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(8, 8, 100, 200), mask_clip->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeUpdateTest, InlineAddRemoveMask) {
@@ -1008,7 +1020,7 @@ TEST_P(PaintPropertyTreeUpdateTest, InlineAddRemoveMask) {
EXPECT_NE(nullptr, properties->Mask());
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
- EXPECT_EQ(50, mask_clip->ClipRect().Rect().Width());
+ EXPECT_EQ(50, mask_clip->UnsnappedClipRect().Rect().Width());
target->setAttribute(html_names::kStyleAttr, "");
UpdateAllLifecyclePhasesForTest();
@@ -1026,14 +1038,14 @@ TEST_P(PaintPropertyTreeUpdateTest, MaskClipNodeInlineBoundsChange) {
ASSERT_NE(nullptr, properties);
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
- EXPECT_EQ(50, mask_clip->ClipRect().Rect().Width());
+ EXPECT_EQ(50, mask_clip->UnsnappedClipRect().Rect().Width());
GetDocument().getElementById("img")->setAttribute(html_names::kStyleAttr,
"width: 100px");
UpdateAllLifecyclePhasesForTest();
ASSERT_EQ(mask_clip, properties->MaskClip());
- EXPECT_EQ(100, mask_clip->ClipRect().Rect().Width());
+ EXPECT_EQ(100, mask_clip->UnsnappedClipRect().Rect().Width());
}
TEST_P(PaintPropertyTreeUpdateTest, AddRemoveSVGMask) {
@@ -1058,7 +1070,7 @@ TEST_P(PaintPropertyTreeUpdateTest, AddRemoveSVGMask) {
EXPECT_NE(nullptr, properties->Mask());
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
- EXPECT_EQ(FloatRoundedRect(0, 100, 100, 100), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 100, 100, 100), mask_clip->UnsnappedClipRect());
GetDocument().getElementById("rect")->removeAttribute("mask");
UpdateAllLifecyclePhasesForTest();
@@ -1085,13 +1097,13 @@ TEST_P(PaintPropertyTreeUpdateTest, SVGMaskTargetBoundsChange) {
EXPECT_NE(nullptr, properties->Mask());
const auto* mask_clip = properties->MaskClip();
ASSERT_NE(nullptr, mask_clip);
- EXPECT_EQ(FloatRoundedRect(0, 50, 100, 150), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 50, 100, 150), mask_clip->UnsnappedClipRect());
GetDocument().getElementById("rect")->setAttribute("width", "200");
UpdateAllLifecyclePhasesForTest();
EXPECT_NE(nullptr, properties->Effect());
EXPECT_NE(nullptr, properties->Mask());
- EXPECT_EQ(FloatRoundedRect(0, 50, 100, 150), mask_clip->ClipRect());
+ EXPECT_EQ(FloatRoundedRect(0, 50, 100, 150), mask_clip->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeUpdateTest, WillTransformChangeAboveFixed) {
@@ -1184,7 +1196,7 @@ TEST_P(PaintPropertyTreeUpdateTest, SVGViewportContainerOverflowChange) {
const auto* properties = PaintPropertiesForElement("target");
ASSERT_NE(nullptr, properties);
EXPECT_EQ(FloatRect(0, 0, 30, 40),
- properties->OverflowClip()->ClipRect().Rect());
+ properties->OverflowClip()->UnsnappedClipRect().Rect());
GetDocument().getElementById("target")->setAttribute("overflow", "visible");
UpdateAllLifecyclePhasesForTest();
@@ -1195,7 +1207,7 @@ TEST_P(PaintPropertyTreeUpdateTest, SVGViewportContainerOverflowChange) {
properties = PaintPropertiesForElement("target");
ASSERT_NE(nullptr, properties);
EXPECT_EQ(FloatRect(0, 0, 30, 40),
- properties->OverflowClip()->ClipRect().Rect());
+ properties->OverflowClip()->UnsnappedClipRect().Rect());
}
TEST_P(PaintPropertyTreeUpdateTest, SVGForeignObjectOverflowChange) {
@@ -1210,7 +1222,7 @@ TEST_P(PaintPropertyTreeUpdateTest, SVGForeignObjectOverflowChange) {
const auto* properties = PaintPropertiesForElement("target");
ASSERT_NE(nullptr, properties);
EXPECT_EQ(FloatRect(10, 20, 30, 40),
- properties->OverflowClip()->ClipRect().Rect());
+ properties->OverflowClip()->UnsnappedClipRect().Rect());
GetDocument().getElementById("target")->setAttribute("overflow", "visible");
UpdateAllLifecyclePhasesForTest();
@@ -1221,7 +1233,7 @@ TEST_P(PaintPropertyTreeUpdateTest, SVGForeignObjectOverflowChange) {
properties = PaintPropertiesForElement("target");
ASSERT_NE(nullptr, properties);
EXPECT_EQ(FloatRect(10, 20, 30, 40),
- properties->OverflowClip()->ClipRect().Rect());
+ properties->OverflowClip()->UnsnappedClipRect().Rect());
}
TEST_P(PaintPropertyTreeBuilderTest, OmitOverflowClipOnSelectionChange) {
@@ -1280,13 +1292,13 @@ TEST_P(PaintPropertyTreeUpdateTest,
EXPECT_EQ(1000000, FragmentAt(flow_thread, 0)
.PaintProperties()
->FragmentClip()
- ->ClipRect()
+ ->UnsnappedClipRect()
.Rect()
.MaxX());
EXPECT_EQ(-999950, FragmentAt(flow_thread, 1)
.PaintProperties()
->FragmentClip()
- ->ClipRect()
+ ->UnsnappedClipRect()
.Rect()
.X());
@@ -1298,13 +1310,13 @@ TEST_P(PaintPropertyTreeUpdateTest,
EXPECT_EQ(1000000, FragmentAt(flow_thread, 0)
.PaintProperties()
->FragmentClip()
- ->ClipRect()
+ ->UnsnappedClipRect()
.Rect()
.MaxX());
EXPECT_EQ(-999750, FragmentAt(flow_thread, 1)
.PaintProperties()
->FragmentClip()
- ->ClipRect()
+ ->UnsnappedClipRect()
.Rect()
.X());
}
@@ -1522,7 +1534,7 @@ TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForImage) {
FloatSize corner(2, 2);
FloatRoundedRect::Radii radii(corner, corner, corner, corner);
EXPECT_EQ(FloatRoundedRect(FloatRect(8, 8, 8, 8), radii),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
// We should update clip rect on border radius change.
target->setAttribute(html_names::kStyleAttr,
@@ -1532,7 +1544,7 @@ TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForImage) {
ASSERT_TRUE(properties->OverflowClip());
radii.Expand(1);
EXPECT_EQ(FloatRoundedRect(FloatRect(8, 8, 8, 8), radii),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
// We should update clip rect on padding change.
target->setAttribute(
@@ -1547,7 +1559,7 @@ TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForImage) {
FloatRoundedRect(FloatRect(12, 9, 2, 4),
FloatRoundedRect::Radii(FloatSize(0, 2), FloatSize(1, 2),
FloatSize(), FloatSize(1, 0))),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForVideo) {
@@ -1570,14 +1582,14 @@ TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForVideo) {
ASSERT_TRUE(properties);
ASSERT_TRUE(properties->OverflowClip());
EXPECT_EQ(FloatRoundedRect(8, 8, 8, 8),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
target->setAttribute(html_names::kStyleAttr, "object-fit: cover");
UpdateAllLifecyclePhasesForTest();
ASSERT_EQ(properties, PaintPropertiesForElement("target"));
ASSERT_TRUE(properties->OverflowClip());
EXPECT_EQ(FloatRoundedRect(8, 8, 8, 8),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
// We need OverflowClip for object-fit: cover, too.
target->setAttribute(html_names::kStyleAttr, "object-fit: none");
@@ -1585,7 +1597,7 @@ TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForVideo) {
ASSERT_EQ(properties, PaintPropertiesForElement("target"));
ASSERT_TRUE(properties->OverflowClip());
EXPECT_EQ(FloatRoundedRect(8, 8, 8, 8),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
// We should update clip rect on padding change.
target->setAttribute(html_names::kStyleAttr,
@@ -1594,7 +1606,7 @@ TEST_P(PaintPropertyTreeUpdateTest, OverflowClipUpdateForVideo) {
ASSERT_EQ(properties, PaintPropertiesForElement("target"));
ASSERT_TRUE(properties->OverflowClip());
EXPECT_EQ(FloatRoundedRect(12, 9, 2, 4),
- properties->OverflowClip()->ClipRect());
+ properties->OverflowClip()->UnsnappedClipRect());
}
TEST_P(PaintPropertyTreeUpdateTest, ChangingClipPath) {
@@ -1690,7 +1702,8 @@ TEST_P(PaintPropertyTreeUpdateTest, ChangeDuringAnimation) {
target->SetStyle(std::move(style));
EXPECT_TRUE(target->NeedsPaintPropertyUpdate());
GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
const auto* transform_node =
target->FirstFragment().PaintProperties()->Transform();
@@ -1718,7 +1731,8 @@ TEST_P(PaintPropertyTreeUpdateTest, ChangeDuringAnimation) {
target->SetStyle(std::move(style));
EXPECT_TRUE(target->NeedsPaintPropertyUpdate());
GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
ASSERT_EQ(transform_node,
target->FirstFragment().PaintProperties()->Transform());
@@ -1737,7 +1751,8 @@ TEST_P(PaintPropertyTreeUpdateTest, ChangeDuringAnimation) {
target->SetStyle(std::move(style));
EXPECT_TRUE(target->NeedsPaintPropertyUpdate());
GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
ASSERT_EQ(transform_node,
target->FirstFragment().PaintProperties()->Transform());
@@ -1756,7 +1771,8 @@ TEST_P(PaintPropertyTreeUpdateTest, BackfaceVisibilityInvalidatesProperties) {
auto* span = GetDocument().getElementById("span");
span->setAttribute(html_names::kStyleAttr, "backface-visibility: hidden;");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(span->GetLayoutObject()->NeedsPaintPropertyUpdate());
}
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing.cc b/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
index d4c99d65d9f..6e7140526b6 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing.cc
@@ -99,12 +99,6 @@ void PaintTiming::SetFirstMeaningfulPaint(
"loading,rail,devtools.timeline", "firstMeaningfulPaint", swap_stamp,
"frame", ToTraceValue(GetFrame()), "afterUserInput", had_input);
- InteractiveDetector* interactive_detector(
- InteractiveDetector::From(*GetSupplementable()));
- if (interactive_detector) {
- interactive_detector->OnFirstMeaningfulPaintDetected(swap_stamp, had_input);
- }
-
// Notify FMP for UMA only if there's no user input before FMP, so that layout
// changes caused by user interactions wouldn't be considered as FMP.
if (had_input == FirstMeaningfulPaintDetector::kNoUserInput) {
@@ -129,7 +123,7 @@ void PaintTiming::SetTickClockForTesting(const base::TickClock* clock) {
clock_ = clock;
}
-void PaintTiming::Trace(blink::Visitor* visitor) {
+void PaintTiming::Trace(Visitor* visitor) {
visitor->Trace(fmp_detector_);
Supplement<Document>::Trace(visitor);
}
@@ -190,11 +184,11 @@ void PaintTiming::RegisterNotifySwapTime(PaintEvent event,
}
void PaintTiming::ReportSwapTime(PaintEvent event,
- WebWidgetClient::SwapResult result,
+ WebSwapResult result,
base::TimeTicks timestamp) {
DCHECK(IsMainThread());
// If the swap fails for any reason, we use the timestamp when the SwapPromise
- // was broken. |result| == WebWidgetClient::SwapResult::kDidNotSwapSwapFails
+ // was broken. |result| == WebSwapResult::kDidNotSwapSwapFails
// usually means the compositor decided not swap because there was no actual
// damage, which can happen when what's being painted isn't visible. In this
// case, the timestamp will be consistent with the case where the swap
@@ -246,6 +240,11 @@ void PaintTiming::SetFirstContentfulPaintSwap(base::TimeTicks stamp) {
GetFrame()->Loader().Progress().DidFirstContentfulPaint();
NotifyPaintTimingChanged();
fmp_detector_->NotifyFirstContentfulPaint(first_contentful_paint_swap_);
+ InteractiveDetector* interactive_detector =
+ InteractiveDetector::From(*GetSupplementable());
+ if (interactive_detector) {
+ interactive_detector->OnFirstContentfulPaint(first_contentful_paint_swap_);
+ }
}
void PaintTiming::SetFirstImagePaintSwap(base::TimeTicks stamp) {
@@ -256,12 +255,12 @@ void PaintTiming::SetFirstImagePaintSwap(base::TimeTicks stamp) {
NotifyPaintTimingChanged();
}
-void PaintTiming::ReportSwapResultHistogram(
- WebWidgetClient::SwapResult result) {
- DEFINE_STATIC_LOCAL(EnumerationHistogram, did_swap_histogram,
- ("PageLoad.Internal.Renderer.PaintTiming.SwapResult",
- WebWidgetClient::SwapResult::kSwapResultMax));
- did_swap_histogram.Count(result);
+void PaintTiming::ReportSwapResultHistogram(WebSwapResult result) {
+ DEFINE_STATIC_LOCAL(
+ EnumerationHistogram, did_swap_histogram,
+ ("PageLoad.Internal.Renderer.PaintTiming.SwapResult",
+ static_cast<uint32_t>(WebSwapResult::kSwapResultLast) + 1));
+ did_swap_histogram.Count(static_cast<uint32_t>(result));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing.h b/chromium/third_party/blink/renderer/core/paint/paint_timing.h
index ffb1ae2133f..61e4358f997 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing.h
@@ -8,7 +8,7 @@
#include <memory>
#include "base/macros.h"
-#include "third_party/blink/public/web/web_widget_client.h"
+#include "third_party/blink/public/web/web_swap_result.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
#include "third_party/blink/renderer/core/paint/paint_event.h"
@@ -31,8 +31,7 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
USING_GARBAGE_COLLECTED_MIXIN(PaintTiming);
friend class FirstMeaningfulPaintDetector;
using ReportTimeCallback =
- WTF::CrossThreadOnceFunction<void(WebWidgetClient::SwapResult,
- base::TimeTicks)>;
+ WTF::CrossThreadOnceFunction<void(WebSwapResult, base::TimeTicks)>;
public:
static const char kSupplementName[];
@@ -99,16 +98,14 @@ class CORE_EXPORT PaintTiming final : public GarbageCollected<PaintTiming>,
}
void RegisterNotifySwapTime(PaintEvent, ReportTimeCallback);
- void ReportSwapTime(PaintEvent,
- WebWidgetClient::SwapResult,
- base::TimeTicks timestamp);
+ void ReportSwapTime(PaintEvent, WebSwapResult, base::TimeTicks timestamp);
- void ReportSwapResultHistogram(WebWidgetClient::SwapResult);
+ void ReportSwapResultHistogram(WebSwapResult);
// The caller owns the |clock| which must outlive the PaintTiming.
void SetTickClockForTesting(const base::TickClock* clock);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
LocalFrame* GetFrame() const;
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
index 8c16c5fc6ce..a5940c4d407 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -3,7 +3,8 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
-#include "third_party/blink/public/platform/web_input_event.h"
+#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/platform/web_float_rect.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -21,13 +22,16 @@
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/text_paint_timing_detector.h"
#include "third_party/blink/renderer/core/style/style_fetched_image.h"
+#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
+#include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/graphics/paint/float_clip_rect.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
+#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -45,19 +49,22 @@ bool IsBackgroundImageContentful(const LayoutObject& object,
const Image& image) {
// Background images attached to <body> or <html> are likely for background
// purpose, so we rule them out.
- if (object.IsLayoutView() || object.IsBody() || object.IsDocumentElement()) {
+ if (IsA<LayoutView>(object) || object.IsBody() ||
+ object.IsDocumentElement()) {
return false;
}
// Generated images are excluded here, as they are likely to serve for
// background purpose.
- if (!image.IsBitmapImage() && !image.IsStaticBitmapImage() &&
- !image.IsSVGImage() && !image.IsPlaceholderImage())
+ if (!IsA<BitmapImage>(image) && !IsA<StaticBitmapImage>(image) &&
+ !IsA<SVGImage>(image) && !image.IsPlaceholderImage())
return false;
return true;
}
} // namespace
+bool IgnorePaintTimingScope::should_ignore_ = false;
+
PaintTimingDetector::PaintTimingDetector(LocalFrameView* frame_view)
: frame_view_(frame_view),
text_paint_timing_detector_(
@@ -99,7 +106,11 @@ void PaintTimingDetector::NotifyBackgroundImagePaint(
const Node* node,
const Image* image,
const StyleFetchedImage* style_image,
- const PropertyTreeState& current_paint_chunk_properties) {
+ const PropertyTreeState& current_paint_chunk_properties,
+ const IntRect& image_border) {
+ if (IgnorePaintTimingScope::ShouldIgnore())
+ return;
+
DCHECK(image);
DCHECK(style_image->CachedImage());
if (!node)
@@ -117,7 +128,7 @@ void PaintTimingDetector::NotifyBackgroundImagePaint(
return;
detector.GetImagePaintTimingDetector()->RecordImage(
*object, image->Size(), *style_image->CachedImage(),
- current_paint_chunk_properties, style_image);
+ current_paint_chunk_properties, style_image, &image_border);
}
// static
@@ -126,6 +137,9 @@ void PaintTimingDetector::NotifyImagePaint(
const IntSize& intrinsic_size,
const ImageResourceContent* cached_image,
const PropertyTreeState& current_paint_chunk_properties) {
+ if (IgnorePaintTimingScope::ShouldIgnore())
+ return;
+
LocalFrameView* frame_view = object.GetFrameView();
if (!frame_view)
return;
@@ -136,7 +150,7 @@ void PaintTimingDetector::NotifyImagePaint(
return;
detector.GetImagePaintTimingDetector()->RecordImage(
object, intrinsic_size, *cached_image, current_paint_chunk_properties,
- nullptr);
+ nullptr, nullptr);
}
void PaintTimingDetector::NotifyImageFinished(
@@ -162,8 +176,11 @@ void PaintTimingDetector::NotifyImageRemoved(
}
}
-void PaintTimingDetector::StopRecordingLargestContentfulPaint() {
- DCHECK(frame_view_);
+void PaintTimingDetector::OnInputOrScroll() {
+ // If we have already stopped, then abort.
+ if (!is_recording_largest_contentful_paint_)
+ return;
+
// TextPaintTimingDetector is used for both Largest Contentful Paint and for
// Element Timing. Therefore, here we only want to stop recording Largest
// Contentful Paint.
@@ -173,21 +190,29 @@ void PaintTimingDetector::StopRecordingLargestContentfulPaint() {
if (image_paint_timing_detector_)
image_paint_timing_detector_->StopRecordEntries();
largest_contentful_paint_calculator_ = nullptr;
+
+ DCHECK_EQ(first_input_or_scroll_notified_timestamp_, base::TimeTicks());
+ first_input_or_scroll_notified_timestamp_ = base::TimeTicks::Now();
+ DidChangePerformanceTiming();
+ is_recording_largest_contentful_paint_ = false;
}
void PaintTimingDetector::NotifyInputEvent(WebInputEvent::Type type) {
+ // A single keyup event should be ignored. It could be caused by user actions
+ // such as refreshing via Ctrl+R.
if (type == WebInputEvent::kMouseMove || type == WebInputEvent::kMouseEnter ||
- type == WebInputEvent::kMouseLeave ||
+ type == WebInputEvent::kMouseLeave || type == WebInputEvent::kKeyUp ||
WebInputEvent::IsPinchGestureEventType(type)) {
return;
}
- StopRecordingLargestContentfulPaint();
+ OnInputOrScroll();
}
-void PaintTimingDetector::NotifyScroll(ScrollType scroll_type) {
- if (scroll_type != kUserScroll && scroll_type != kCompositorScroll)
+void PaintTimingDetector::NotifyScroll(mojom::blink::ScrollType scroll_type) {
+ if (scroll_type != mojom::blink::ScrollType::kUser &&
+ scroll_type != mojom::blink::ScrollType::kCompositor)
return;
- StopRecordingLargestContentfulPaint();
+ OnInputOrScroll();
}
bool PaintTimingDetector::NeedToNotifyInputOrScroll() const {
@@ -332,6 +357,9 @@ ScopedPaintTimingDetectorBlockPaintHook*
void ScopedPaintTimingDetectorBlockPaintHook::EmplaceIfNeeded(
const LayoutBoxModelObject& aggregator,
const PropertyTreeState& property_tree_state) {
+ if (IgnorePaintTimingScope::ShouldIgnore())
+ return;
+
// |reset_top_| is unset when |aggregator| is anonymous so that each
// aggregation corresponds to an element. See crbug.com/988593. When set,
// |top_| becomes |this|, and |top_| is restored to the previous value when
@@ -402,7 +430,7 @@ void PaintTimingCallbackManagerImpl::
void PaintTimingCallbackManagerImpl::ReportPaintTime(
std::unique_ptr<PaintTimingCallbackManager::CallbackQueue> frame_callbacks,
- WebWidgetClient::SwapResult result,
+ WebSwapResult result,
base::TimeTicks paint_time) {
while (!frame_callbacks->empty()) {
std::move(frame_callbacks->front()).Run(paint_time);
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
index f27a0e04ce2..82391ba7022 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -5,8 +5,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
-#include "third_party/blink/public/platform/web_input_event.h"
-#include "third_party/blink/public/web/web_widget_client.h"
+#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/web/web_swap_result.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/paint/paint_timing_visualizer.h"
@@ -86,7 +86,7 @@ class PaintTimingCallbackManagerImpl final
void ReportPaintTime(
std::unique_ptr<std::queue<
PaintTimingCallbackManager::LocalThreadCallback>> frame_callbacks,
- WebWidgetClient::SwapResult,
+ WebSwapResult,
base::TimeTicks paint_time);
void Trace(Visitor* visitor) override;
@@ -124,7 +124,8 @@ class CORE_EXPORT PaintTimingDetector
const Node*,
const Image*,
const StyleFetchedImage*,
- const PropertyTreeState& current_paint_chunk_properties);
+ const PropertyTreeState& current_paint_chunk_properties,
+ const IntRect& image_border);
static void NotifyImagePaint(
const LayoutObject&,
const IntSize& intrinsic_size,
@@ -138,7 +139,7 @@ class CORE_EXPORT PaintTimingDetector
void NotifyPaintFinished();
void NotifyInputEvent(WebInputEvent::Type);
bool NeedToNotifyInputOrScroll() const;
- void NotifyScroll(ScrollType);
+ void NotifyScroll(mojom::blink::ScrollType);
// The returned value indicates whether the candidates have changed.
bool NotifyIfChangedLargestImagePaint(base::TimeTicks, uint64_t size);
bool NotifyIfChangedLargestTextPaint(base::TimeTicks, uint64_t size);
@@ -171,6 +172,9 @@ class CORE_EXPORT PaintTimingDetector
uint64_t LargestImagePaintSize() const { return largest_image_paint_size_; }
base::TimeTicks LargestTextPaint() const { return largest_text_paint_time_; }
uint64_t LargestTextPaintSize() const { return largest_text_paint_size_; }
+ base::TimeTicks FirstInputOrScrollNotifiedTimestamp() const {
+ return first_input_or_scroll_notified_timestamp_;
+ }
void UpdateLargestContentfulPaintCandidate();
@@ -178,7 +182,8 @@ class CORE_EXPORT PaintTimingDetector
void Trace(Visitor* visitor);
private:
- void StopRecordingLargestContentfulPaint();
+ // Method called to stop recording the Largest Contentful Paint.
+ void OnInputOrScroll();
bool HasLargestImagePaintChanged(base::TimeTicks, uint64_t size) const;
bool HasLargestTextPaintChanged(base::TimeTicks, uint64_t size) const;
Member<LocalFrameView> frame_view_;
@@ -188,7 +193,14 @@ class CORE_EXPORT PaintTimingDetector
// image paint is found.
Member<ImagePaintTimingDetector> image_paint_timing_detector_;
+ // This member lives for as long as the largest contentful paint is being
+ // computed. However, it is initialized lazily, so it may be nullptr because
+ // it has not yet been initialized or because we have stopped computing LCP.
Member<LargestContentfulPaintCalculator> largest_contentful_paint_calculator_;
+ // Time at which the first input or scroll is notified to PaintTimingDetector,
+ // hence causing LCP to stop being recorded. This is the same time at which
+ // |largest_contentful_paint_calculator_| is set to nullptr.
+ base::TimeTicks first_input_or_scroll_notified_timestamp_;
Member<PaintTimingCallbackManagerImpl> callback_manager_;
@@ -200,6 +212,7 @@ class CORE_EXPORT PaintTimingDetector
// Largest text information.
base::TimeTicks largest_text_paint_time_;
uint64_t largest_text_paint_size_ = 0;
+ bool is_recording_largest_contentful_paint_ = true;
};
// Largest Text Paint and Text Element Timing aggregate text nodes by these
@@ -251,7 +264,7 @@ class ScopedPaintTimingDetectorBlockPaintHook {
const LayoutBoxModelObject& aggregator_;
const PropertyTreeState& property_tree_state_;
- Member<TextPaintTimingDetector> detector_;
+ TextPaintTimingDetector* detector_;
IntRect aggregated_visual_rect_;
};
base::Optional<Data> data_;
@@ -260,9 +273,27 @@ class ScopedPaintTimingDetectorBlockPaintHook {
DISALLOW_COPY_AND_ASSIGN(ScopedPaintTimingDetectorBlockPaintHook);
};
+// Creates a scope to ignore paint timing, e.g. when we are painting contents
+// under opacity:0.
+class IgnorePaintTimingScope {
+ STACK_ALLOCATED();
+
+ public:
+ IgnorePaintTimingScope() : auto_reset_(&should_ignore_, true) {}
+ ~IgnorePaintTimingScope() = default;
+
+ static bool ShouldIgnore() { return should_ignore_; }
+
+ private:
+ base::AutoReset<bool> auto_reset_;
+ static bool should_ignore_;
+};
+
// static
inline void PaintTimingDetector::NotifyTextPaint(
const IntRect& text_visual_rect) {
+ if (IgnorePaintTimingScope::ShouldIgnore())
+ return;
ScopedPaintTimingDetectorBlockPaintHook::AggregateTextPaint(text_visual_rect);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index 91577fd6474..4fffe2ebb46 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -16,6 +16,9 @@
#include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
@@ -28,6 +31,42 @@
namespace blink {
+namespace {
+
+// Locate or/and set up the current FragmentData object. This may involve
+// creating it, or resetting an existing one. If |allow_reset| is set, we're
+// allowed to clear old FragmentData objects.
+NGPrePaintInfo SetupFragmentData(const NGFragmentChildIterator& iterator,
+ bool allow_reset) {
+ DCHECK(iterator->GetLayoutObject());
+ const LayoutObject& object = *iterator->GetLayoutObject();
+ FragmentData* fragment_data = &object.GetMutableForPainting().FirstFragment();
+ // TODO(crbug.com/1043787): Add support for block fragmentation. Furthermore,
+ // what's here is mostly gross, and we need to come up with something
+ // better. The way FragmentData works (and is stored) vs. the way
+ // NGPhysicalFragment works is less than ideal.
+ fragment_data->ClearNextFragment();
+ if (const NGFragmentItem* fragment_item = iterator->FragmentItem()) {
+ // We're in an inline formatting context.
+ if (fragment_item->IsFirstForNode()) {
+ // This is the first fragment generated for the node (i.e. we're on the
+ // first line and first fragmentainer (column) that this node occurs
+ // in). Now is our chance to reset everything (the number or size of
+ // fragments may have changed since last time). All the other fragments
+ // will be visited in due course.
+ if (allow_reset && !object.IsBox()) {
+ // For text and non-atomic inlines we now reset the visual rect. The
+ // visual rect will be set and expanded, as we visit each individual
+ // fragment.
+ fragment_data->SetVisualRect(IntRect());
+ }
+ }
+ }
+ return NGPrePaintInfo(iterator, *fragment_data);
+}
+
+} // anonymous namespace
+
void PrePaintTreeWalk::WalkTree(LocalFrameView& root_frame_view) {
if (root_frame_view.ShouldThrottleRendering()) {
// Skip the throttled frame. Will update it when it becomes unthrottled.
@@ -135,7 +174,7 @@ void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {
}
#endif
- Walk(*view);
+ Walk(*view, /* iterator */ nullptr);
#if DCHECK_IS_ON()
view->AssertSubtreeClearedPaintInvalidationFlags();
#endif
@@ -167,7 +206,7 @@ bool HasBlockingTouchEventHandler(const LocalFrame& frame,
}
bool HasBlockingTouchEventHandler(const LayoutObject& object) {
- if (object.IsLayoutView()) {
+ if (IsA<LayoutView>(object)) {
auto* frame = object.GetFrame();
if (HasBlockingTouchEventHandler(*frame, *frame->DomWindow()))
return true;
@@ -312,10 +351,23 @@ void PrePaintTreeWalk::CheckTreeBuilderContextState(
}
void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
+ const NGFragmentChildIterator* iterator,
PrePaintTreeWalkContext& context) {
PaintInvalidatorContext& paint_invalidator_context =
context.paint_invalidator_context;
+ base::Optional<NGPrePaintInfo> pre_paint_info_storage;
+ NGPrePaintInfo* pre_paint_info = nullptr;
+ if (iterator) {
+ bool allow_reset = context.tree_builder_context.has_value()
+#if DCHECK_IS_ON()
+ && context.tree_builder_context->is_actually_needed
+#endif
+ ;
+ pre_paint_info_storage.emplace(SetupFragmentData(*iterator, allow_reset));
+ pre_paint_info = &pre_paint_info_storage.value();
+ }
+
// This must happen before updatePropertiesForSelf, because the latter reads
// some of the state computed here.
UpdateAuxiliaryObjectProperties(object, context);
@@ -324,7 +376,9 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
PaintPropertyChangeType property_changed =
PaintPropertyChangeType::kUnchanged;
if (context.tree_builder_context) {
- property_tree_builder.emplace(object, *context.tree_builder_context);
+ property_tree_builder.emplace(object, pre_paint_info,
+ *context.tree_builder_context);
+
property_changed =
std::max(property_changed, property_tree_builder->UpdateForSelf());
@@ -341,7 +395,8 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
UpdateEffectiveAllowedTouchAction(object, context);
if (paint_invalidator_.InvalidatePaint(
- object, base::OptionalOrNullptr(context.tree_builder_context),
+ object, pre_paint_info,
+ base::OptionalOrNullptr(context.tree_builder_context),
paint_invalidator_context))
needs_invalidate_chrome_client_ = true;
@@ -389,6 +444,8 @@ void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
if (context.clip_changed && object.HasLayer())
ToLayoutBoxModelObject(object).Layer()->SetNeedsRepaint();
+ // TODO(crbug.com/1058792): Allow multiple fragments for composited elements
+ // (passing |iterator| here is probably part of the solution).
CompositingLayerPropertyUpdater::Update(object);
}
@@ -403,7 +460,140 @@ LocalFrameView* FindWebViewPluginContentFrameView(
return nullptr;
}
-void PrePaintTreeWalk::Walk(const LayoutObject& object) {
+void PrePaintTreeWalk::WalkNGChildren(const LayoutObject* parent,
+ NGFragmentChildIterator* iterator) {
+ for (; !iterator->IsAtEnd(); iterator->Advance()) {
+ const LayoutObject* object = (*iterator)->GetLayoutObject();
+ if (const auto* fragment_item = (*iterator)->FragmentItem()) {
+ // Line boxes are not interesting. They have no paint effects. Descend
+ // directly into children.
+ bool descend_directly = fragment_item->Type() == NGFragmentItem::kLine;
+ if (!descend_directly && fragment_item->IsInlineBox() &&
+ !fragment_item->BoxFragment()) {
+ // Likewise for culled inlines.
+ descend_directly = true;
+ object->GetMutableForPainting().ClearPaintFlags();
+ }
+ if (descend_directly) {
+ WalkChildren(/* parent */ nullptr, iterator);
+ continue;
+ }
+ }
+ DCHECK(object);
+ Walk(*object, iterator);
+ }
+}
+
+void PrePaintTreeWalk::WalkLegacyChildren(const LayoutObject& object) {
+ if (const LayoutBox* layout_box = ToLayoutBoxOrNull(&object)) {
+ if (layout_box->CanTraversePhysicalFragments()) {
+ // Enter NG child fragment traversal. We'll stay in this mode for all
+ // descendants that support fragment traversal. We'll re-enter
+ // LayoutObject traversal for descendants that don't support it. This only
+ // works correctly if we're not block-fragmented, though, so DCHECK for
+ // that.
+ DCHECK_EQ(layout_box->PhysicalFragmentCount(), 1u);
+ const NGPhysicalBoxFragment& fragment =
+ To<NGPhysicalBoxFragment>(*layout_box->GetPhysicalFragment(0));
+ NGFragmentChildIterator child_iterator(fragment);
+ WalkNGChildren(&object, &child_iterator);
+ return;
+ }
+ }
+
+ for (const LayoutObject* child = object.SlowFirstChild(); child;
+ child = child->NextSibling()) {
+ if (child->IsLayoutMultiColumnSpannerPlaceholder()) {
+ child->GetMutableForPainting().ClearPaintFlags();
+ continue;
+ }
+ Walk(*child, /* iterator */ nullptr);
+ }
+
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled())
+ return;
+
+ const LayoutBlock* block = DynamicTo<LayoutBlock>(&object);
+ if (!block)
+ return;
+ const auto* positioned_objects = block->PositionedObjects();
+ if (!positioned_objects)
+ return;
+
+ // If we have performed NG fragment traversal in any part of the subtree, we
+ // may have missed certain out-of-flow positioned objects. LayoutNG fragments
+ // are always children of their containing block, while the structure of the
+ // LayoutObject tree corresponds more closely to that of the DOM tree.
+ //
+ // Example: if we assume that flexbox isn't natively supported in LayoutNG:
+ //
+ // <div id="flex" style="display:flex; position:relative;">
+ // <div id="flexitem">
+ // <div id="abs" style="position:absolute;"></div>
+ // <div id="regular"></div>
+ //
+ // If we let |object| be #flex, it will be handled by legacy LayoutObject
+ // traversal, while #flexitem, on the other hand, can traverse its NG child
+ // fragments. However, #regular will be the only child fragment of #flexitem,
+ // since the containing block for #abs is #flex. So we'd miss it, unless we
+ // walk it now.
+ for (const LayoutBox* box : *positioned_objects) {
+ // It's important that objects that have already been walked be left alone.
+ // Otherwise, we might calculate the wrong offsets (and overwrite the
+ // correct ones) in case of out-of-flow positioned objects whose containing
+ // block is a relatively positioned non-atomic inline (such objects will
+ // already have been properly walked, since we don't switch engines within
+ // an inline formatting context). Put differently, the code here will only
+ // do the right thing if |object| is truly the containing block of the
+ // positioned objects in its list (which isn't the case if the containing
+ // block is a non-atomic inline).
+ if (!ObjectRequiresPrePaint(*box) &&
+ !ObjectRequiresTreeBuilderContext(*box))
+ continue;
+ DCHECK_EQ(box->Container(), &object);
+ Walk(*box, /* iterator */ nullptr);
+ }
+}
+
+void PrePaintTreeWalk::WalkChildren(const LayoutObject* object,
+ const NGFragmentChildIterator* iterator) {
+ DCHECK(iterator || object);
+
+ if (!iterator) {
+ // We're not doing LayoutNG fragment traversal of this object.
+ WalkLegacyChildren(*object);
+ return;
+ }
+
+ // If we are performing LayoutNG fragment traversal, but this object doesn't
+ // support that, we need to switch back to legacy LayoutObject traversal for
+ // its children. We're then also assuming that we're either not
+ // block-fragmenting, or that this is monolithic content. We may re-enter
+ // LayoutNG fragment traversal if we get to a descendant that supports that.
+ if (object && !object->CanTraversePhysicalFragments()) {
+ DCHECK(
+ !object->FlowThreadContainingBlock() ||
+ (object->IsBox() && ToLayoutBox(object)->GetPaginationBreakability() ==
+ LayoutBox::kForbidBreaks));
+ WalkLegacyChildren(*object);
+ return;
+ }
+
+ // Traverse child NG fragments.
+ NGFragmentChildIterator child_iterator(iterator->Descend());
+ WalkNGChildren(object, &child_iterator);
+}
+
+void PrePaintTreeWalk::Walk(const LayoutObject& object,
+ const NGFragmentChildIterator* iterator) {
+ const NGPhysicalBoxFragment* physical_fragment = nullptr;
+ bool is_last_fragment = true;
+ if (iterator) {
+ physical_fragment = (*iterator)->BoxFragment();
+ if (const auto* fragment_item = (*iterator)->FragmentItem())
+ is_last_fragment = fragment_item->IsLastForNode();
+ }
+
// We need to be careful not to have a reference to the parent context, since
// this reference will be to the context_storage_ memory which may be
// reallocated during this function call.
@@ -447,8 +637,10 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object) {
context().tree_builder_context->clip_changed = false;
}
- WalkInternal(object, context());
- object.NotifyDisplayLockDidPrePaint(DisplayLockLifecycleTarget::kSelf);
+ WalkInternal(object, iterator, context());
+
+ if (is_last_fragment)
+ object.NotifyDisplayLockDidPrePaint(DisplayLockLifecycleTarget::kSelf);
bool child_walk_blocked = object.PrePaintBlockedByDisplayLock(
DisplayLockLifecycleTarget::kChildren);
@@ -469,14 +661,7 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object) {
}
if (!child_walk_blocked) {
- for (const LayoutObject* child = object.SlowFirstChild(); child;
- child = child->NextSibling()) {
- if (child->IsLayoutMultiColumnSpannerPlaceholder()) {
- child->GetMutableForPainting().ClearPaintFlags();
- continue;
- }
- Walk(*child);
- }
+ WalkChildren(&object, iterator);
if (object.IsLayoutEmbeddedContent()) {
const LayoutEmbeddedContent& layout_embedded_content =
@@ -505,8 +690,8 @@ void PrePaintTreeWalk::Walk(const LayoutObject& object) {
object.NotifyDisplayLockDidPrePaint(DisplayLockLifecycleTarget::kChildren);
}
-
- object.GetMutableForPainting().ClearPaintFlags();
+ if (is_last_fragment)
+ object.GetMutableForPainting().ClearPaintFlags();
context_storage_.pop_back();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
index fa95f4bd2fe..5ded2b4f51c 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk.h
@@ -14,6 +14,7 @@ namespace blink {
class LayoutObject;
class LocalFrameView;
+class NGFragmentChildIterator;
// This class walks the whole layout tree, beginning from the root
// LocalFrameView, across frame boundaries. Helper classes are called for each
@@ -101,8 +102,13 @@ class CORE_EXPORT PrePaintTreeWalk {
// very big stack frames. Splitting the heavy lifting to a separate function
// makes sure the stack frame is freed prior to making a recursive call.
// See https://crbug.com/781301 .
- NOINLINE void WalkInternal(const LayoutObject&, PrePaintTreeWalkContext&);
- void Walk(const LayoutObject&);
+ NOINLINE void WalkInternal(const LayoutObject&,
+ const NGFragmentChildIterator*,
+ PrePaintTreeWalkContext&);
+ void WalkNGChildren(const LayoutObject* parent, NGFragmentChildIterator*);
+ void WalkLegacyChildren(const LayoutObject&);
+ void WalkChildren(const LayoutObject*, const NGFragmentChildIterator*);
+ void Walk(const LayoutObject&, const NGFragmentChildIterator*);
bool NeedsTreeBuilderContextUpdate(const LocalFrameView&,
const PrePaintTreeWalkContext&);
diff --git a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
index b49316436fa..3665e2c0f48 100644
--- a/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/pre_paint_tree_walk_test.cc
@@ -164,7 +164,8 @@ TEST_P(PrePaintTreeWalkTest, ClearSubsequenceCachingClipChange) {
EXPECT_FALSE(child_paint_layer->NeedsPaintPhaseFloat());
parent->setAttribute(html_names::kClassAttr, "clip");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(child_paint_layer->SelfNeedsRepaint());
}
@@ -190,7 +191,8 @@ TEST_P(PrePaintTreeWalkTest, ClearSubsequenceCachingClipChange2DTransform) {
EXPECT_FALSE(child_paint_layer->NeedsPaintPhaseFloat());
parent->setAttribute(html_names::kClassAttr, "clip");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(child_paint_layer->SelfNeedsRepaint());
}
@@ -219,7 +221,8 @@ TEST_P(PrePaintTreeWalkTest, ClearSubsequenceCachingClipChangePosAbs) {
// This changes clips for absolute-positioned descendants of "child" but not
// normal-position ones, which are already clipped to 50x50.
parent->setAttribute(html_names::kClassAttr, "clip");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(child_paint_layer->SelfNeedsRepaint());
}
@@ -248,7 +251,8 @@ TEST_P(PrePaintTreeWalkTest, ClearSubsequenceCachingClipChangePosFixed) {
// This changes clips for absolute-positioned descendants of "child" but not
// normal-position ones, which are already clipped to 50x50.
parent->setAttribute(html_names::kClassAttr, "clip");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(child_paint_layer->SelfNeedsRepaint());
}
@@ -272,7 +276,8 @@ TEST_P(PrePaintTreeWalkTest, ClipChangeRepaintsDescendants) {
)HTML");
GetDocument().getElementById("parent")->removeAttribute("style");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
auto* greatgrandchild = GetLayoutObjectByElementId("greatgrandchild");
auto* paint_layer = ToLayoutBoxModelObject(greatgrandchild)->Layer();
@@ -320,7 +325,8 @@ TEST_P(PrePaintTreeWalkTest, ClipChangeHasRadius) {
auto* target = GetDocument().getElementById("target");
auto* target_object = ToLayoutBoxModelObject(target->GetLayoutObject());
target->setAttribute(html_names::kStyleAttr, "border-radius: 5px");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(target_object->Layer()->SelfNeedsRepaint());
// And should not trigger any assert failure.
UpdateAllLifecyclePhasesForTest();
@@ -413,7 +419,8 @@ TEST_P(PrePaintTreeWalkTest, EffectiveTouchActionStyleUpdate) {
GetDocument()
.getElementById("touchaction")
->setAttribute(html_names::kClassAttr, "touchaction");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(ancestor.EffectiveAllowedTouchActionChanged());
EXPECT_TRUE(touchaction.EffectiveAllowedTouchActionChanged());
EXPECT_FALSE(descendant.EffectiveAllowedTouchActionChanged());
diff --git a/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc b/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
index 133aa11e6d4..47048c35bf9 100644
--- a/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -141,11 +141,11 @@ void ReplacedPainter::Paint(const PaintInfo& paint_info) {
}
if (local_paint_info.phase != PaintPhase::kForeground &&
- local_paint_info.phase != PaintPhase::kSelection &&
+ local_paint_info.phase != PaintPhase::kSelectionDragImage &&
!layout_replaced_.CanHaveChildren())
return;
- if (local_paint_info.phase == PaintPhase::kSelection &&
+ if (local_paint_info.phase == PaintPhase::kSelectionDragImage &&
!layout_replaced_.IsSelected())
return;
@@ -200,7 +200,7 @@ bool ReplacedPainter::ShouldPaint(const ScopedPaintState& paint_state) const {
if (paint_info.phase != PaintPhase::kForeground &&
paint_info.phase != PaintPhase::kForcedColorsModeBackplate &&
!ShouldPaintSelfOutline(paint_info.phase) &&
- paint_info.phase != PaintPhase::kSelection &&
+ paint_info.phase != PaintPhase::kSelectionDragImage &&
paint_info.phase != PaintPhase::kMask &&
!ShouldPaintSelfBlockBackground(paint_info.phase))
return false;
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc
index 759d8bd72f7..c7ef1d33d18 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
#include "third_party/blink/renderer/core/layout/layout_replaced.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/box_model_object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -74,7 +75,7 @@ void ScopedBoxContentsPaintState::AdjustForBoxContents(const LayoutBox& box) {
// with a smaller cull rect, and the scrolling document contents are under the
// layer of document element which will use infinite cull rect calculated in
// PaintLayerPainter::AdjustForPaintProperties().
- if (box.IsLayoutView() && input_paint_info_.GetCullRect().IsInfinite())
+ if (IsA<LayoutView>(box) && input_paint_info_.GetCullRect().IsInfinite())
return;
adjusted_paint_info_.emplace(input_paint_info_);
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h
index 158e6727141..97bf34b9272 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_paint_state.h
@@ -28,9 +28,10 @@ class ScopedPaintState {
STACK_ALLOCATED();
public:
- ScopedPaintState(const LayoutObject& object, const PaintInfo& paint_info)
- : fragment_to_paint_(paint_info.FragmentToPaint(object)),
- input_paint_info_(paint_info) {
+ ScopedPaintState(const LayoutObject& object,
+ const PaintInfo& paint_info,
+ const FragmentData* fragment_data)
+ : fragment_to_paint_(fragment_data), input_paint_info_(paint_info) {
if (!fragment_to_paint_) {
// The object has nothing to paint in the current fragment.
// TODO(wangxianzhu): Use DCHECK(fragment_to_paint_) in PaintOffset()
@@ -55,9 +56,16 @@ class ScopedPaintState {
}
}
+ ScopedPaintState(const LayoutObject& object, const PaintInfo& paint_info)
+ : ScopedPaintState(object,
+ paint_info,
+ paint_info.FragmentToPaint(object)) {}
+
ScopedPaintState(const NGPhysicalFragment& fragment,
const PaintInfo& paint_info)
- : ScopedPaintState(*fragment.GetLayoutObject(), paint_info) {}
+ : ScopedPaintState(*fragment.GetLayoutObject(),
+ paint_info,
+ paint_info.FragmentToPaint(fragment)) {}
~ScopedPaintState() {
if (paint_offset_translation_as_drawing_)
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
index e293f0caa1d..cf1ec8de0e0 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
@@ -25,47 +25,59 @@
#include "third_party/blink/renderer/core/paint/scoped_svg_paint_state.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
-#include "third_party/blink/renderer/core/paint/svg_mask_painter.h"
+#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
namespace blink {
-ScopedSVGPaintState::~ScopedSVGPaintState() {
- if (filter_) {
- DCHECK(SVGResourcesCache::CachedResourcesForLayoutObject(object_));
- DCHECK(
- SVGResourcesCache::CachedResourcesForLayoutObject(object_)->Filter() ==
- filter_);
- DCHECK(filter_recording_context_);
- SVGFilterPainter(*filter_).FinishEffect(object_,
- *filter_recording_context_);
-
- // Reset the paint info after the filter effect has been completed.
- filter_paint_info_ = nullptr;
- }
+static void PaintFilteredContent(GraphicsContext& context,
+ const LayoutObject& object,
+ const DisplayItemClient& display_item_client,
+ FilterData* filter_data) {
+ if (DrawingRecorder::UseCachedDrawingIfPossible(context, display_item_client,
+ DisplayItem::kSVGFilter))
+ return;
- if (masker_) {
+ DrawingRecorder recorder(context, display_item_client,
+ DisplayItem::kSVGFilter);
+ sk_sp<PaintFilter> image_filter = filter_data->CreateFilter();
+ context.Save();
+
+ // Clip drawing of filtered image to the minimum required paint rect.
+ const FloatRect object_bounds = object.StrokeBoundingBox();
+ const FloatRect paint_rect = filter_data->MapRect(object_bounds);
+ context.ClipRect(paint_rect);
+
+ // Use the union of the pre-image and the post-image as the layer bounds.
+ const FloatRect layer_bounds = UnionRect(object_bounds, paint_rect);
+ context.BeginLayer(1, SkBlendMode::kSrcOver, &layer_bounds, kColorFilterNone,
+ std::move(image_filter));
+ context.EndLayer();
+ context.Restore();
+}
+
+ScopedSVGPaintState::~ScopedSVGPaintState() {
+ if (filter_data_ && filter_data_->UpdateStateOnFinish()) {
DCHECK(SVGResourcesCache::CachedResourcesForLayoutObject(object_));
DCHECK(
- SVGResourcesCache::CachedResourcesForLayoutObject(object_)->Masker() ==
- masker_);
- SVGMaskPainter(*masker_).FinishEffect(object_, GetPaintInfo().context);
+ SVGResourcesCache::CachedResourcesForLayoutObject(object_)->Filter());
+ if (filter_recording_context_) {
+ filter_data_->UpdateContent(
+ filter_recording_context_->GetPaintRecord(paint_info_));
+ filter_recording_context_ = nullptr;
+ }
+ PaintFilteredContent(paint_info_.context, object_, display_item_client_,
+ filter_data_);
+ filter_data_ = nullptr;
}
}
-bool ScopedSVGPaintState::ApplyClipMaskAndFilterIfNecessary() {
+bool ScopedSVGPaintState::ApplyEffects() {
#if DCHECK_IS_ON()
DCHECK(!apply_clip_mask_and_filter_if_necessary_called_);
apply_clip_mask_and_filter_if_necessary_called_ = true;
#endif
- // In CAP we should early exit once the paint property state has been
- // applied, because all meta (non-drawing) display items are ignored in
- // CAP. However we can't simply omit them because there are still
- // non-composited painting (e.g. SVG filters in particular) that rely on
- // these meta display items.
ApplyPaintPropertyState();
// When rendering clip paths as masks, only geometric operations should be
@@ -93,8 +105,7 @@ bool ScopedSVGPaintState::ApplyClipMaskAndFilterIfNecessary() {
SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object_);
- if (!ApplyMaskIfNecessary(resources))
- return false;
+ ApplyMaskIfNecessary(resources);
if (is_svg_root_or_foreign_object) {
// PaintLayerPainter takes care of filter.
@@ -102,7 +113,6 @@ bool ScopedSVGPaintState::ApplyClipMaskAndFilterIfNecessary() {
} else if (!ApplyFilterIfNecessary(resources)) {
return false;
}
-
return true;
}
@@ -129,25 +139,20 @@ void ScopedSVGPaintState::ApplyPaintPropertyState() {
else if (const auto* clip_path_clip = properties->ClipPathClip())
state.SetClip(*clip_path_clip);
scoped_paint_chunk_properties_.emplace(
- paint_controller, state, object_,
+ paint_controller, state, display_item_client_,
DisplayItem::PaintPhaseToSVGEffectType(GetPaintInfo().phase));
}
void ScopedSVGPaintState::ApplyClipIfNecessary() {
if (object_.StyleRef().ClipPath()) {
clip_path_clipper_.emplace(GetPaintInfo().context, object_,
- PhysicalOffset());
+ display_item_client_, PhysicalOffset());
}
}
-bool ScopedSVGPaintState::ApplyMaskIfNecessary(SVGResources* resources) {
- if (LayoutSVGResourceMasker* masker =
- resources ? resources->Masker() : nullptr) {
- if (!SVGMaskPainter(*masker).PrepareEffect(object_, GetPaintInfo().context))
- return false;
- masker_ = masker;
- }
- return true;
+void ScopedSVGPaintState::ApplyMaskIfNecessary(SVGResources* resources) {
+ if (resources && resources->Masker())
+ mask_painter_.emplace(paint_info_.context, object_, display_item_client_);
}
static bool HasReferenceFilterOnly(const ComputedStyle& style) {
@@ -162,27 +167,20 @@ static bool HasReferenceFilterOnly(const ComputedStyle& style) {
bool ScopedSVGPaintState::ApplyFilterIfNecessary(SVGResources* resources) {
if (!resources)
return !HasReferenceFilterOnly(object_.StyleRef());
-
LayoutSVGResourceFilter* filter = resources->Filter();
if (!filter)
return true;
- filter_recording_context_ =
- std::make_unique<SVGFilterRecordingContext>(GetPaintInfo().context);
- filter_ = filter;
- GraphicsContext* filter_context = SVGFilterPainter(*filter).PrepareEffect(
- object_, *filter_recording_context_);
- if (!filter_context)
+ filter->ClearInvalidationMask();
+ filter_data_ = SVGFilterPainter(*filter).PrepareEffect(object_);
+ // If we have no filter data (== the filter was invalid) or if we
+ // don't need to update the source graphics, we can short-circuit
+ // here.
+ if (!filter_data_ || !filter_data_->ContentNeedsUpdate())
return false;
-
// Because the filter needs to cache its contents we replace the context
// during filtering with the filter's context.
- filter_paint_info_ =
- std::make_unique<PaintInfo>(*filter_context, paint_info_);
-
- // Because we cache the filter contents and do not invalidate on paint
- // invalidation rect changes, we need to paint the entire filter region
- // so elements outside the initial paint (due to scrolling, etc) paint.
- filter_paint_info_->ApplyInfiniteCullRect();
+ filter_recording_context_ =
+ std::make_unique<SVGFilterRecordingContext>(paint_info_);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h
index 479b12c09f7..8d467e7b4a2 100644
--- a/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h
+++ b/chromium/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h
@@ -30,14 +30,14 @@
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/svg_filter_painter.h"
+#include "third_party/blink/renderer/core/paint/svg_mask_painter.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
namespace blink {
+class FilterData;
class LayoutObject;
-class LayoutSVGResourceFilter;
-class LayoutSVGResourceMasker;
class SVGResources;
// Hooks up the correct paint property transform node.
@@ -81,28 +81,31 @@ class ScopedSVGPaintState {
public:
ScopedSVGPaintState(const LayoutObject& object, const PaintInfo& paint_info)
+ : ScopedSVGPaintState(object, paint_info, object) {}
+
+ ScopedSVGPaintState(const LayoutObject& object,
+ const PaintInfo& paint_info,
+ const DisplayItemClient& display_item_client)
: object_(object),
paint_info_(paint_info),
- filter_(nullptr),
- masker_(nullptr) {}
+ display_item_client_(display_item_client),
+ filter_data_(nullptr) {}
~ScopedSVGPaintState();
- PaintInfo& GetPaintInfo() {
- return filter_paint_info_ ? *filter_paint_info_ : paint_info_;
+ const PaintInfo& GetPaintInfo() const {
+ return filter_recording_context_ ? filter_recording_context_->GetPaintInfo()
+ : paint_info_;
}
// Return true if these operations aren't necessary or if they are
// successfully applied.
- bool ApplyClipMaskAndFilterIfNecessary();
+ bool ApplyEffects();
private:
void ApplyPaintPropertyState();
void ApplyClipIfNecessary();
-
- // Return true if no masking is necessary or if the mask is successfully
- // applied.
- bool ApplyMaskIfNecessary(SVGResources*);
+ void ApplyMaskIfNecessary(SVGResources*);
// Return true if no filtering is necessary or if the filter is successfully
// applied.
@@ -110,12 +113,12 @@ class ScopedSVGPaintState {
const LayoutObject& object_;
PaintInfo paint_info_;
- std::unique_ptr<PaintInfo> filter_paint_info_;
- LayoutSVGResourceFilter* filter_;
- LayoutSVGResourceMasker* masker_;
+ const DisplayItemClient& display_item_client_;
+ FilterData* filter_data_;
base::Optional<ClipPathClipper> clip_path_clipper_;
std::unique_ptr<SVGFilterRecordingContext> filter_recording_context_;
base::Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties_;
+ base::Optional<SVGMaskPainter> mask_painter_;
#if DCHECK_IS_ON()
bool apply_clip_mask_and_filter_if_necessary_called_ = false;
#endif
diff --git a/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.cc b/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
index ab01fef7a7c..df26ad02982 100644
--- a/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
@@ -19,7 +19,6 @@
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.h"
namespace blink {
@@ -30,10 +29,7 @@ void ScrollableAreaPainter::PaintResizer(GraphicsContext& context,
if (!GetScrollableArea().GetLayoutBox()->StyleRef().HasResize())
return;
- IntRect abs_rect = GetScrollableArea().ResizerCornerRect(
- GetScrollableArea().GetLayoutBox()->PixelSnappedBorderBoxRect(
- GetScrollableArea().Layer()->SubpixelAccumulation()),
- kResizerForPointer);
+ IntRect abs_rect = GetScrollableArea().ResizerCornerRect(kResizerForPointer);
if (abs_rect.IsEmpty())
return;
abs_rect.MoveBy(paint_offset);
@@ -73,18 +69,15 @@ void ScrollableAreaPainter::PaintResizer(GraphicsContext& context,
void ScrollableAreaPainter::RecordResizerScrollHitTestData(
GraphicsContext& context,
- const PhysicalOffset& paint_offset,
- const DisplayItemClient& client) {
+ const PhysicalOffset& paint_offset) {
if (!GetScrollableArea().GetLayoutBox()->CanResize())
return;
- IntRect touch_rect = scrollable_area_->ResizerCornerRect(
- GetScrollableArea().GetLayoutBox()->PixelSnappedBorderBoxRect(
- paint_offset),
- kResizerForTouch);
+ IntRect touch_rect = scrollable_area_->ResizerCornerRect(kResizerForTouch);
touch_rect.MoveBy(RoundedIntPoint(paint_offset));
- ScrollHitTestDisplayItem::Record(
- context, client, DisplayItem::kResizerScrollHitTest, nullptr, touch_rect);
+ context.GetPaintController().RecordScrollHitTestData(
+ DisplayItemClientForCorner(), DisplayItem::kResizerScrollHitTest, nullptr,
+ touch_rect);
}
void ScrollableAreaPainter::DrawPlatformResizerImage(
@@ -201,18 +194,16 @@ void ScrollableAreaPainter::PaintScrollbar(GraphicsContext& context,
Scrollbar& scrollbar,
const CullRect& cull_rect,
const IntPoint& paint_offset) {
- // We create PaintOffsetTranslation for scrollable area, so the rounded
- // paint offset is always zero.
// TODO(crbug.com/1020913): We should not round paint_offset but should
// consider subpixel accumulation when painting scrollbars.
- DCHECK_EQ(paint_offset, IntPoint());
IntRect rect = scrollbar.FrameRect();
+ rect.MoveBy(paint_offset);
if (!cull_rect.Intersects(rect))
return;
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
scrollbar.IsCustomScrollbar()) {
- scrollbar.Paint(context);
+ scrollbar.Paint(context, paint_offset);
return;
}
diff --git a/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.h b/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.h
index 54d27f793e8..9b702249b5a 100644
--- a/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/scrollable_area_painter.h
@@ -38,10 +38,8 @@ class ScrollableAreaPainter {
// Records a scroll hit test data to force main thread handling of events
// in the expanded resizer touch area.
- void RecordResizerScrollHitTestData(
- GraphicsContext&,
- const PhysicalOffset& paint_offset,
- const DisplayItemClient& background_client);
+ void RecordResizerScrollHitTestData(GraphicsContext&,
+ const PhysicalOffset& paint_offset);
private:
void DrawPlatformResizerImage(GraphicsContext&,
@@ -54,7 +52,7 @@ class ScrollableAreaPainter {
PaintLayerScrollableArea& GetScrollableArea() const;
const DisplayItemClient& DisplayItemClientForCorner() const;
- Member<PaintLayerScrollableArea> scrollable_area_;
+ PaintLayerScrollableArea* scrollable_area_;
DISALLOW_COPY_AND_ASSIGN(ScrollableAreaPainter);
};
diff --git a/chromium/third_party/blink/renderer/core/paint/selection_painting_utils.cc b/chromium/third_party/blink/renderer/core/paint/selection_painting_utils.cc
index 98cd2b17a71..d4ed87b374c 100644
--- a/chromium/third_party/blink/renderer/core/paint/selection_painting_utils.cc
+++ b/chromium/third_party/blink/renderer/core/paint/selection_painting_utils.cc
@@ -73,7 +73,7 @@ Color SelectionColor(const Document& document,
// If the element is unselectable, or we are only painting the selection,
// don't override the foreground color with the selection foreground color.
if ((node && !NodeIsSelectable(style, node)) ||
- (global_paint_flags & kGlobalPaintSelectionOnly))
+ (global_paint_flags & kGlobalPaintSelectionDragImageOnly))
return style.VisitedDependentColor(color_property);
if (scoped_refptr<ComputedStyle> pseudo_style =
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_container_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_container_painter.cc
index 77847cb1415..0da8574d1e4 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_container_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_container_painter.cc
@@ -32,10 +32,8 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
if (svg_svg_element && svg_svg_element->HasEmptyViewBox())
return;
- PaintInfo paint_info_before_filtering(paint_info);
-
if (SVGModelObjectPainter(layout_svg_container_)
- .CullRectSkipsPainting(paint_info_before_filtering)) {
+ .CullRectSkipsPainting(paint_info)) {
return;
}
@@ -44,6 +42,7 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
// 2) Complexity: Difficulty updating clips when ancestor transforms change.
// This is why we use an infinite cull rect if there is a transform. Non-svg
// content, does this in PaintLayerPainter::PaintSingleFragment.
+ PaintInfo paint_info_before_filtering(paint_info);
if (layout_svg_container_.StyleRef().HasTransform()) {
paint_info_before_filtering.ApplyInfiniteCullRect();
} else if (const auto* properties =
@@ -59,7 +58,8 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
base::Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
if (layout_svg_container_.IsSVGViewportContainer() &&
SVGLayoutSupport::IsOverflowHidden(layout_svg_container_)) {
- const auto* fragment = paint_info.FragmentToPaint(layout_svg_container_);
+ const auto* fragment =
+ paint_info_before_filtering.FragmentToPaint(layout_svg_container_);
if (!fragment)
return;
const auto* properties = fragment->PaintProperties();
@@ -68,9 +68,9 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
// properties are ready.
if (properties && properties->OverflowClip()) {
scoped_paint_chunk_properties.emplace(
- paint_info.context.GetPaintController(),
+ paint_info_before_filtering.context.GetPaintController(),
*properties->OverflowClip(), layout_svg_container_,
- paint_info.DisplayItemTypeForClipping());
+ paint_info_before_filtering.DisplayItemTypeForClipping());
}
}
@@ -78,13 +78,13 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
paint_info_before_filtering);
bool continue_rendering = true;
if (paint_state.GetPaintInfo().phase == PaintPhase::kForeground)
- continue_rendering = paint_state.ApplyClipMaskAndFilterIfNecessary();
+ continue_rendering = paint_state.ApplyEffects();
if (continue_rendering) {
for (LayoutObject* child = layout_svg_container_.FirstChild(); child;
child = child->NextSibling()) {
- if (child->IsSVGForeignObject()) {
- SVGForeignObjectPainter(ToLayoutSVGForeignObject(*child))
+ if (auto* foreign_object = DynamicTo<LayoutSVGForeignObject>(*child)) {
+ SVGForeignObjectPainter(*foreign_object)
.PaintLayer(paint_state.GetPaintInfo());
} else {
child->Paint(paint_state.GetPaintInfo());
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.cc
index 66b1ae84e13..47552d0011e 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.cc
@@ -12,157 +12,65 @@
#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
#include "third_party/blink/renderer/core/svg/svg_filter_element.h"
#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
-#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
#include "third_party/blink/renderer/platform/graphics/filters/source_graphic.h"
-#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
namespace blink {
-GraphicsContext* SVGFilterRecordingContext::BeginContent() {
- // Create a new context so the contents of the filter can be drawn and cached.
- paint_controller_ = std::make_unique<PaintController>();
- context_ = std::make_unique<GraphicsContext>(*paint_controller_);
-
- // Use initial_context_'s current paint chunk properties so that any new
+SVGFilterRecordingContext::SVGFilterRecordingContext(
+ const PaintInfo& initial_paint_info)
+ // Create a new context so the contents of the filter can be drawn and
+ // cached.
+ : paint_controller_(std::make_unique<PaintController>()),
+ context_(std::make_unique<GraphicsContext>(*paint_controller_)),
+ paint_info_(*context_, initial_paint_info) {
+ // Use initial_paint_info's current paint chunk properties so that any new
// chunk created during painting the content will be in the correct state.
paint_controller_->UpdateCurrentPaintChunkProperties(
- base::nullopt,
- initial_context_.GetPaintController().CurrentPaintChunkProperties());
-
- return context_.get();
+ nullptr, initial_paint_info.context.GetPaintController()
+ .CurrentPaintChunkProperties());
+ // Because we cache the filter contents and do not invalidate on paint
+ // invalidation rect changes, we need to paint the entire filter region so
+ // elements outside the initial paint (due to scrolling, etc) paint.
+ paint_info_.ApplyInfiniteCullRect();
}
-sk_sp<PaintRecord> SVGFilterRecordingContext::EndContent(
- const FloatRect& bounds) {
- // Use the context that contains the filtered content.
- DCHECK(paint_controller_);
- DCHECK(context_);
- context_->BeginRecording(bounds);
- paint_controller_->CommitNewDisplayItems();
-
- paint_controller_->GetPaintArtifact().Replay(
- *context_,
- initial_context_.GetPaintController().CurrentPaintChunkProperties());
+SVGFilterRecordingContext::~SVGFilterRecordingContext() = default;
- sk_sp<PaintRecord> content = context_->EndRecording();
- // Content is cached by the source graphic so temporaries can be freed.
- paint_controller_ = nullptr;
- context_ = nullptr;
- return content;
-}
-
-void SVGFilterRecordingContext::Abort() {
- if (!paint_controller_)
- return;
- EndContent(FloatRect());
-}
-
-static void PaintFilteredContent(GraphicsContext& context,
- const LayoutObject& object,
- const FloatRect& bounds,
- FilterEffect* effect) {
- if (DrawingRecorder::UseCachedDrawingIfPossible(context, object,
- DisplayItem::kSVGFilter))
- return;
-
- DrawingRecorder recorder(context, object, DisplayItem::kSVGFilter);
- sk_sp<PaintFilter> image_filter =
- paint_filter_builder::Build(effect, kInterpolationSpaceSRGB);
- context.Save();
-
- // Clip drawing of filtered image to the minimum required paint rect.
- context.ClipRect(effect->MapRect(object.StrokeBoundingBox()));
-
- context.BeginLayer(1, SkBlendMode::kSrcOver, &bounds, kColorFilterNone,
- std::move(image_filter));
- context.EndLayer();
- context.Restore();
+sk_sp<PaintRecord> SVGFilterRecordingContext::GetPaintRecord(
+ const PaintInfo& initial_paint_info) {
+ paint_controller_->CommitNewDisplayItems();
+ return paint_controller_->GetPaintArtifact().GetPaintRecord(
+ initial_paint_info.context.GetPaintController()
+ .CurrentPaintChunkProperties());
}
-GraphicsContext* SVGFilterPainter::PrepareEffect(
- const LayoutObject& object,
- SVGFilterRecordingContext& recording_context) {
- filter_.ClearInvalidationMask();
-
- SVGResourceClient* client = SVGResources::GetClient(object);
- if (FilterData* filter_data = filter_.GetFilterDataForClient(client)) {
+FilterData* SVGFilterPainter::PrepareEffect(const LayoutObject& object) {
+ SVGElementResourceClient* client = SVGResources::GetClient(object);
+ if (FilterData* filter_data = client->GetFilterData()) {
// If the filterData already exists we do not need to record the content
// to be filtered. This can occur if the content was previously recorded
// or we are in a cycle.
- if (filter_data->state_ == FilterData::kPaintingFilter)
- filter_data->state_ = FilterData::kPaintingFilterCycleDetected;
-
- if (filter_data->state_ == FilterData::kRecordingContent)
- filter_data->state_ = FilterData::kRecordingContentCycleDetected;
-
- return nullptr;
+ filter_data->UpdateStateOnPrepare();
+ return filter_data;
}
auto* node_map = MakeGarbageCollected<SVGFilterGraphNodeMap>();
- FilterEffectBuilder builder(object.ObjectBoundingBox(), 1);
+ FilterEffectBuilder builder(SVGResources::ReferenceBoxForEffects(object), 1);
Filter* filter = builder.BuildReferenceFilter(
To<SVGFilterElement>(*filter_.GetElement()), nullptr, node_map);
if (!filter || !filter->LastEffect())
return nullptr;
- IntRect source_region = EnclosingIntRect(
- Intersection(filter->FilterRegion(), object.StrokeBoundingBox()));
+ IntRect source_region = EnclosingIntRect(object.StrokeBoundingBox());
filter->GetSourceGraphic()->SetSourceRect(source_region);
- auto* filter_data = MakeGarbageCollected<FilterData>();
- filter_data->last_effect = filter->LastEffect();
- filter_data->node_map = node_map;
- DCHECK_EQ(filter_data->state_, FilterData::kInitial);
-
+ auto* filter_data =
+ MakeGarbageCollected<FilterData>(filter->LastEffect(), node_map);
// TODO(pdr): Can this be moved out of painter?
- filter_.SetFilterDataForClient(client, filter_data);
- filter_data->state_ = FilterData::kRecordingContent;
- return recording_context.BeginContent();
-}
-
-void SVGFilterPainter::FinishEffect(
- const LayoutObject& object,
- SVGFilterRecordingContext& recording_context) {
- SVGResourceClient* client = SVGResources::GetClient(object);
- FilterData* filter_data = filter_.GetFilterDataForClient(client);
- if (!filter_data) {
- // Our state was torn down while we were being painted (selection style for
- // <text> can have this effect), or it was never created (invalid filter.)
- // In the former case we may have been in the process of recording content,
- // so make sure we put recording state into a consistent state.
- recording_context.Abort();
- return;
- }
-
- // A painting cycle can occur when an FeImage references a source that
- // makes use of the FeImage itself. This is the first place we would hit
- // the cycle so we reset the state and continue.
- if (filter_data->state_ == FilterData::kPaintingFilterCycleDetected) {
- filter_data->state_ = FilterData::kPaintingFilter;
- return;
- }
- if (filter_data->state_ == FilterData::kRecordingContentCycleDetected) {
- filter_data->state_ = FilterData::kRecordingContent;
- return;
- }
-
- // Check for RecordingContent here because we may can be re-painting
- // without re-recording the contents to be filtered.
- Filter* filter = filter_data->last_effect->GetFilter();
- FloatRect bounds = filter->FilterRegion();
- if (filter_data->state_ == FilterData::kRecordingContent) {
- DCHECK(filter->GetSourceGraphic());
- sk_sp<PaintRecord> content = recording_context.EndContent(bounds);
- paint_filter_builder::BuildSourceGraphic(filter->GetSourceGraphic(),
- std::move(content), bounds);
- filter_data->state_ = FilterData::kReadyToPaint;
- }
-
- DCHECK_EQ(filter_data->state_, FilterData::kReadyToPaint);
- filter_data->state_ = FilterData::kPaintingFilter;
- PaintFilteredContent(recording_context.PaintingContext(), object, bounds,
- filter_data->last_effect);
- filter_data->state_ = FilterData::kReadyToPaint;
+ client->SetFilterData(filter_data);
+ return filter_data;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.h b/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.h
index 7dd90ff7c54..f38d6937347 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/svg_filter_painter.h
@@ -7,32 +7,31 @@
#include <memory>
#include "base/macros.h"
-#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
-#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
+#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
+class FilterData;
+class GraphicsContext;
class LayoutObject;
class LayoutSVGResourceFilter;
+class PaintController;
class SVGFilterRecordingContext {
USING_FAST_MALLOC(SVGFilterRecordingContext);
public:
- explicit SVGFilterRecordingContext(GraphicsContext& initial_context)
- : initial_context_(initial_context) {}
+ explicit SVGFilterRecordingContext(const PaintInfo&);
+ ~SVGFilterRecordingContext();
- GraphicsContext* BeginContent();
- sk_sp<PaintRecord> EndContent(const FloatRect&);
- void Abort();
-
- GraphicsContext& PaintingContext() const { return initial_context_; }
+ const PaintInfo& GetPaintInfo() const { return paint_info_; }
+ sk_sp<PaintRecord> GetPaintRecord(const PaintInfo&);
private:
std::unique_ptr<PaintController> paint_controller_;
std::unique_ptr<GraphicsContext> context_;
- GraphicsContext& initial_context_;
+ PaintInfo paint_info_;
DISALLOW_COPY_AND_ASSIGN(SVGFilterRecordingContext);
};
@@ -42,11 +41,9 @@ class SVGFilterPainter {
public:
SVGFilterPainter(LayoutSVGResourceFilter& filter) : filter_(filter) {}
- // Returns the context that should be used to paint the filter contents, or
- // null if the content should not be recorded.
- GraphicsContext* PrepareEffect(const LayoutObject&,
- SVGFilterRecordingContext&);
- void FinishEffect(const LayoutObject&, SVGFilterRecordingContext&);
+ // Returns the FilterData for the filter effect, or null if the
+ // filter is invalid.
+ FilterData* PrepareEffect(const LayoutObject&);
private:
LayoutSVGResourceFilter& filter_;
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_foreign_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_foreign_object_painter.cc
index 4d7405fcc7c..fa811d7863e 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_foreign_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_foreign_object_painter.cc
@@ -6,9 +6,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/paint/block_painter.h"
-#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
@@ -19,7 +17,7 @@ namespace blink {
void SVGForeignObjectPainter::PaintLayer(const PaintInfo& paint_info) {
if (paint_info.phase != PaintPhase::kForeground &&
- paint_info.phase != PaintPhase::kSelection)
+ paint_info.phase != PaintPhase::kSelectionDragImage)
return;
// Early out in the case of trying to paint an image filter before
@@ -51,14 +49,13 @@ void SVGForeignObjectPainter::PaintLayer(const PaintInfo& paint_info) {
}
void SVGForeignObjectPainter::Paint(const PaintInfo& paint_info) {
- PaintInfo paint_info_before_filtering(paint_info);
- ScopedSVGPaintState paint_state(layout_svg_foreign_object_,
- paint_info_before_filtering);
-
- if (paint_state.GetPaintInfo().phase == PaintPhase::kForeground &&
- !paint_state.ApplyClipMaskAndFilterIfNecessary())
+ ScopedSVGPaintState paint_state(layout_svg_foreign_object_, paint_info);
+ // ScopedSVGPaintState only applies masks (and clips-within-clips)
+ // here and thus does not mutate PaintInfo, so we can use the passed
+ // in PaintInfo below.
+ if (paint_info.phase == PaintPhase::kForeground &&
+ !paint_state.ApplyEffects())
return;
-
BlockPainter(layout_svg_foreign_object_).Paint(paint_info);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
index de9deb79d00..e3b5622f87d 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_image_painter.cc
@@ -27,25 +27,23 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
!layout_svg_image_.ImageResource()->HasImage())
return;
- PaintInfo paint_info_before_filtering(paint_info);
-
if (SVGModelObjectPainter(layout_svg_image_)
- .CullRectSkipsPainting(paint_info_before_filtering)) {
+ .CullRectSkipsPainting(paint_info)) {
return;
}
// Images cannot have children so do not call TransformCullRect.
ScopedSVGTransformState transform_state(
- paint_info_before_filtering, layout_svg_image_,
+ paint_info, layout_svg_image_,
layout_svg_image_.LocalToSVGParentTransform());
{
- ScopedSVGPaintState paint_state(layout_svg_image_,
- paint_info_before_filtering);
- if (paint_state.ApplyClipMaskAndFilterIfNecessary() &&
+ ScopedSVGPaintState paint_state(layout_svg_image_, paint_info);
+ if (paint_state.ApplyEffects() &&
!DrawingRecorder::UseCachedDrawingIfPossible(
paint_state.GetPaintInfo().context, layout_svg_image_,
paint_state.GetPaintInfo().phase)) {
- SVGModelObjectPainter::RecordHitTestData(layout_svg_image_, paint_info);
+ SVGModelObjectPainter::RecordHitTestData(layout_svg_image_,
+ paint_state.GetPaintInfo());
DrawingRecorder recorder(paint_state.GetPaintInfo().context,
layout_svg_image_,
paint_state.GetPaintInfo().phase);
@@ -53,8 +51,7 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
}
}
- SVGModelObjectPainter(layout_svg_image_)
- .PaintOutline(paint_info_before_filtering);
+ SVGModelObjectPainter(layout_svg_image_).PaintOutline(paint_info);
}
void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
@@ -64,14 +61,27 @@ void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
if (image_viewport_size.IsEmpty())
return;
- scoped_refptr<Image> image =
- image_resource->GetImage(ExpandedIntSize(image_viewport_size));
+ scoped_refptr<Image> image = image_resource->GetImage(image_viewport_size);
FloatRect dest_rect = layout_svg_image_.ObjectBoundingBox();
- FloatRect src_rect(0, 0, image->width(), image->height());
auto* image_element = To<SVGImageElement>(layout_svg_image_.GetElement());
- image_element->preserveAspectRatio()->CurrentValue()->TransformRect(dest_rect,
- src_rect);
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(&layout_svg_image_);
+ FloatRect src_rect(FloatPoint(), image->SizeAsFloat(respect_orientation));
+ if (respect_orientation && !image->HasDefaultOrientation()) {
+ // We need the oriented source rect for adjusting the aspect ratio
+ FloatSize unadjusted_size(src_rect.Size());
+ image_element->preserveAspectRatio()->CurrentValue()->TransformRect(
+ dest_rect, src_rect);
+
+ // Map the oriented_src_rect back into the src_rect space
+ src_rect =
+ image->CorrectSrcRectForImageOrientation(unadjusted_size, src_rect);
+ } else {
+ image_element->preserveAspectRatio()->CurrentValue()->TransformRect(
+ dest_rect, src_rect);
+ }
+
ScopedInterpolationQuality interpolation_quality_scope(
paint_info.context,
layout_svg_image_.StyleRef().GetInterpolationQuality());
@@ -79,8 +89,9 @@ void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
image_element->GetDecodingModeForPainting(image->paint_image_id());
paint_info.context.DrawImage(
image.get(), decode_mode, dest_rect, &src_rect,
- layout_svg_image_.StyleRef().HasFilterInducingProperty());
- if (!paint_info.context.ContextDisabled() && image_resource->CachedImage() &&
+ layout_svg_image_.StyleRef().HasFilterInducingProperty(),
+ SkBlendMode::kSrcOver, respect_orientation);
+ if (image_resource->CachedImage() &&
image_resource->CachedImage()->IsLoaded()) {
LocalDOMWindow* window = layout_svg_image_.GetDocument().domWindow();
DCHECK(window);
@@ -117,11 +128,12 @@ FloatSize SVGImagePainter::ComputeImageViewportSize() const {
if (cached_image->ErrorOccurred())
return FloatSize();
Image* image = cached_image->GetImage();
- if (image->IsSVGImage()) {
- return ToSVGImage(image)->ConcreteObjectSize(
+ if (auto* svg_image = DynamicTo<SVGImage>(image)) {
+ return svg_image->ConcreteObjectSize(
layout_svg_image_.ObjectBoundingBox().Size());
}
- return FloatSize(image->Size());
+ // The orientation here does not matter. Just use kRespectImageOrientation.
+ return image->SizeAsFloat(kRespectImageOrientation);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_inline_flow_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_inline_flow_box_painter.cc
index a47b291f354..864602286f4 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_inline_flow_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_inline_flow_box_painter.cc
@@ -16,33 +16,34 @@ namespace blink {
void SVGInlineFlowBoxPainter::PaintSelectionBackground(
const PaintInfo& paint_info) {
DCHECK(paint_info.phase == PaintPhase::kForeground ||
- paint_info.phase == PaintPhase::kSelection);
+ paint_info.phase == PaintPhase::kSelectionDragImage);
- PaintInfo child_paint_info(paint_info);
for (InlineBox* child = svg_inline_flow_box_.FirstChild(); child;
child = child->NextOnLine()) {
- if (child->IsSVGInlineTextBox())
- SVGInlineTextBoxPainter(*ToSVGInlineTextBox(child))
- .PaintSelectionBackground(child_paint_info);
- else if (child->IsSVGInlineFlowBox())
- SVGInlineFlowBoxPainter(*ToSVGInlineFlowBox(child))
- .PaintSelectionBackground(child_paint_info);
+ if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(child)) {
+ SVGInlineTextBoxPainter(*svg_inline_text_box)
+ .PaintSelectionBackground(paint_info);
+ } else if (auto* svg_inline_flow_box = DynamicTo<SVGInlineFlowBox>(child)) {
+ SVGInlineFlowBoxPainter(*svg_inline_flow_box)
+ .PaintSelectionBackground(paint_info);
+ }
}
}
void SVGInlineFlowBoxPainter::Paint(const PaintInfo& paint_info,
const LayoutPoint& paint_offset) {
DCHECK(paint_info.phase == PaintPhase::kForeground ||
- paint_info.phase == PaintPhase::kSelection);
+ paint_info.phase == PaintPhase::kSelectionDragImage);
ScopedSVGPaintState paint_state(*LineLayoutAPIShim::ConstLayoutObjectFrom(
svg_inline_flow_box_.GetLineLayoutItem()),
- paint_info);
- if (paint_state.ApplyClipMaskAndFilterIfNecessary()) {
- for (InlineBox* child = svg_inline_flow_box_.FirstChild(); child;
- child = child->NextOnLine())
- child->Paint(paint_state.GetPaintInfo(), paint_offset, LayoutUnit(),
- LayoutUnit());
+ paint_info, svg_inline_flow_box_);
+ if (!paint_state.ApplyEffects())
+ return;
+ for (InlineBox* child = svg_inline_flow_box_.FirstChild(); child;
+ child = child->NextOnLine()) {
+ child->Paint(paint_state.GetPaintInfo(), paint_offset, LayoutUnit(),
+ LayoutUnit());
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
index ea50d27ec60..8dd8f84c994 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_inline_text_box_painter.cc
@@ -74,7 +74,7 @@ LayoutSVGInlineText& SVGInlineTextBoxPainter::InlineText() const {
void SVGInlineTextBoxPainter::Paint(const PaintInfo& paint_info,
const LayoutPoint& paint_offset) {
DCHECK(paint_info.phase == PaintPhase::kForeground ||
- paint_info.phase == PaintPhase::kSelection);
+ paint_info.phase == PaintPhase::kSelectionDragImage);
DCHECK(svg_inline_text_box_.Truncation() == kCNoTruncation);
if (svg_inline_text_box_.GetLineLayoutItem().StyleRef().Visibility() !=
@@ -87,7 +87,7 @@ void SVGInlineTextBoxPainter::Paint(const PaintInfo& paint_info,
// very easy to refactor and reuse the code.
bool have_selection = ShouldPaintSelection(paint_info);
- if (!have_selection && paint_info.phase == PaintPhase::kSelection)
+ if (!have_selection && paint_info.phase == PaintPhase::kSelectionDragImage)
return;
LayoutSVGInlineText& text_layout_object = InlineText();
@@ -213,7 +213,7 @@ void SVGInlineTextBoxPainter::PaintSelectionBackground(
DCHECK(!paint_info.IsPrinting());
- if (paint_info.phase == PaintPhase::kSelection ||
+ if (paint_info.phase == PaintPhase::kSelectionDragImage ||
!ShouldPaintSelection(paint_info))
return;
@@ -507,7 +507,8 @@ void SVGInlineTextBoxPainter::PaintText(
// Eventually draw text using regular style until the start position of the
// selection.
- bool paint_selected_text_only = paint_info.phase == PaintPhase::kSelection;
+ bool paint_selected_text_only =
+ paint_info.phase == PaintPhase::kSelectionDragImage;
if (start_position > 0 && !paint_selected_text_only) {
PaintFlags flags;
if (SetupTextPaint(paint_info, style, resource_mode, flags,
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc
index fbac7c37aa4..b579318ec3b 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.cc
@@ -5,8 +5,8 @@
#include "third_party/blink/renderer/core/paint/svg_mask_painter.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
+#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
-#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
@@ -14,44 +14,48 @@
namespace blink {
-bool SVGMaskPainter::PrepareEffect(const LayoutObject& object,
- GraphicsContext& context) {
- DCHECK(mask_.Style());
- SECURITY_DCHECK(!mask_.NeedsLayout());
-
- mask_.ClearInvalidationMask();
- return mask_.GetElement()->HasChildren();
+SVGMaskPainter::SVGMaskPainter(GraphicsContext& context,
+ const LayoutObject& layout_object,
+ const DisplayItemClient& display_item_client)
+ : context_(context),
+ layout_object_(layout_object),
+ display_item_client_(display_item_client) {
+ DCHECK(layout_object_.StyleRef().SvgStyle().MaskerResource());
}
-void SVGMaskPainter::FinishEffect(const LayoutObject& object,
- GraphicsContext& context) {
- DCHECK(mask_.Style());
- SECURITY_DCHECK(!mask_.NeedsLayout());
-
- base::Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
- const auto* properties = object.FirstFragment().PaintProperties();
+SVGMaskPainter::~SVGMaskPainter() {
+ const auto* properties = layout_object_.FirstFragment().PaintProperties();
// TODO(crbug.com/814815): This condition should be a DCHECK, but for now
// we may paint the object for filters during PrePaint before the
// properties are ready.
- if (properties && properties->Mask()) {
- scoped_paint_chunk_properties.emplace(context.GetPaintController(),
- *properties->Mask(), object,
- DisplayItem::kSVGMask);
- }
-
- AffineTransform content_transformation;
- sk_sp<const PaintRecord> record = mask_.CreatePaintRecord(
- content_transformation, object.ObjectBoundingBox(), context);
+ if (!properties || !properties->Mask())
+ return;
+ ScopedPaintChunkProperties scoped_paint_chunk_properties(
+ context_.GetPaintController(), *properties->Mask(), display_item_client_,
+ DisplayItem::kSVGMask);
- if (DrawingRecorder::UseCachedDrawingIfPossible(context, object,
- DisplayItem::kSVGMask))
+ if (DrawingRecorder::UseCachedDrawingIfPossible(
+ context_, display_item_client_, DisplayItem::kSVGMask))
return;
+ DrawingRecorder recorder(context_, display_item_client_,
+ DisplayItem::kSVGMask);
+
+ const SVGComputedStyle& svg_style = layout_object_.StyleRef().SvgStyle();
+ auto* masker =
+ GetSVGResourceAsType<LayoutSVGResourceMasker>(svg_style.MaskerResource());
+ DCHECK(masker);
+ SECURITY_DCHECK(!masker->NeedsLayout());
+ masker->ClearInvalidationMask();
- DrawingRecorder recorder(context, object, DisplayItem::kSVGMask);
- context.Save();
- context.ConcatCTM(content_transformation);
- context.DrawRecord(std::move(record));
- context.Restore();
+ AffineTransform content_transformation;
+ sk_sp<const PaintRecord> record = masker->CreatePaintRecord(
+ content_transformation,
+ SVGResources::ReferenceBoxForEffects(layout_object_), context_);
+
+ context_.Save();
+ context_.ConcatCTM(content_transformation);
+ context_.DrawRecord(std::move(record));
+ context_.Restore();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.h b/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.h
index af65990bf2e..d7f37cdb526 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/svg_mask_painter.h
@@ -5,26 +5,27 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SVG_MASK_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SVG_MASK_PAINTER_H_
-#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
+class DisplayItemClient;
class GraphicsContext;
class LayoutObject;
-class LayoutSVGResourceMasker;
class SVGMaskPainter {
STACK_ALLOCATED();
public:
- SVGMaskPainter(LayoutSVGResourceMasker& mask) : mask_(mask) {}
-
- bool PrepareEffect(const LayoutObject&, GraphicsContext&);
- void FinishEffect(const LayoutObject&, GraphicsContext&);
+ SVGMaskPainter(GraphicsContext&,
+ const LayoutObject&,
+ const DisplayItemClient&);
+ ~SVGMaskPainter();
private:
- LayoutSVGResourceMasker& mask_;
+ GraphicsContext& context_;
+ const LayoutObject& layout_object_;
+ const DisplayItemClient& display_item_client_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.cc
index dc21e160d02..81e3d4b6b97 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.cc
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
-#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
+#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
namespace blink {
@@ -29,23 +29,19 @@ bool SVGModelObjectPainter::CullRectSkipsPainting(const PaintInfo& paint_info) {
layout_svg_model_object_.VisualRectInLocalSVGCoordinates());
}
-void SVGModelObjectPainter::RecordHitTestData(
- const LayoutSVGModelObject& layout_svg_model_object,
- const PaintInfo& paint_info) {
+void SVGModelObjectPainter::RecordHitTestData(const LayoutObject& svg_object,
+ const PaintInfo& paint_info) {
+ DCHECK(svg_object.IsSVGChild());
DCHECK(paint_info.phase == PaintPhase::kForeground);
// Hit test display items are only needed for compositing. This flag is used
// for for printing and drag images which do not need hit testing.
if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
return;
- auto touch_action = layout_svg_model_object.EffectiveAllowedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
- return;
-
- auto rect =
- LayoutRect(layout_svg_model_object.VisualRectInLocalSVGCoordinates());
- HitTestDisplayItem::Record(paint_info.context, layout_svg_model_object,
- HitTestRect(rect, touch_action));
+ paint_info.context.GetPaintController().RecordHitTestData(
+ svg_object,
+ EnclosingIntRect(svg_object.VisualRectInLocalSVGCoordinates()),
+ svg_object.EffectiveAllowedTouchAction());
}
void SVGModelObjectPainter::PaintOutline(const PaintInfo& paint_info) {
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.h b/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.h
index 7498f380893..21578ed5f37 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/svg_model_object_painter.h
@@ -10,20 +10,22 @@
namespace blink {
struct PaintInfo;
+class LayoutObject;
class LayoutSVGModelObject;
class SVGModelObjectPainter {
STACK_ALLOCATED();
public:
- // Paint a hit test display item and record hit test data. This should be
- // called when painting the background even if there is no other painted
- // content. SVG backgrounds are painted in the kForeground paint phase.
- static void RecordHitTestData(
- const LayoutSVGModelObject& layout_svg_model_object,
- const PaintInfo&);
-
- SVGModelObjectPainter(const LayoutSVGModelObject& layout_svg_model_object)
+ // Expands the bounds of the current paint chunk for hit test, and records
+ // special touch action if any. This should be called when painting the
+ // background even if there is no other painted content. SVG backgrounds are
+ // painted in the kForeground paint phase.
+ static void RecordHitTestData(const LayoutObject& svg_object,
+ const PaintInfo&);
+
+ explicit SVGModelObjectPainter(
+ const LayoutSVGModelObject& layout_svg_model_object)
: layout_svg_model_object_(layout_svg_model_object) {}
// If the object is outside the cull rect, painting can be skipped in most
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc
index fd9eba5ae8b..2b3079f273f 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_root_inline_box_painter.cc
@@ -19,40 +19,42 @@ namespace blink {
void SVGRootInlineBoxPainter::Paint(const PaintInfo& paint_info,
const LayoutPoint& paint_offset) {
DCHECK(paint_info.phase == PaintPhase::kForeground ||
- paint_info.phase == PaintPhase::kSelection);
+ paint_info.phase == PaintPhase::kSelectionDragImage);
bool has_selection =
!paint_info.IsPrinting() && svg_root_inline_box_.IsSelected();
- PaintInfo paint_info_before_filtering(paint_info);
if (has_selection && !DrawingRecorder::UseCachedDrawingIfPossible(
- paint_info_before_filtering.context,
+ paint_info.context,
*LineLayoutAPIShim::ConstLayoutObjectFrom(
svg_root_inline_box_.GetLineLayoutItem()),
- paint_info_before_filtering.phase)) {
- DrawingRecorder recorder(paint_info_before_filtering.context,
+ paint_info.phase)) {
+ DrawingRecorder recorder(paint_info.context,
*LineLayoutAPIShim::ConstLayoutObjectFrom(
svg_root_inline_box_.GetLineLayoutItem()),
- paint_info_before_filtering.phase);
+ paint_info.phase);
for (InlineBox* child = svg_root_inline_box_.FirstChild(); child;
child = child->NextOnLine()) {
- if (child->IsSVGInlineTextBox())
- SVGInlineTextBoxPainter(*ToSVGInlineTextBox(child))
- .PaintSelectionBackground(paint_info_before_filtering);
- else if (child->IsSVGInlineFlowBox())
- SVGInlineFlowBoxPainter(*ToSVGInlineFlowBox(child))
- .PaintSelectionBackground(paint_info_before_filtering);
+ if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(child)) {
+ SVGInlineTextBoxPainter(*svg_inline_text_box)
+ .PaintSelectionBackground(paint_info);
+ } else if (auto* svg_inline_flow_box =
+ DynamicTo<SVGInlineFlowBox>(child)) {
+ SVGInlineFlowBoxPainter(*svg_inline_flow_box)
+ .PaintSelectionBackground(paint_info);
+ }
}
}
ScopedSVGPaintState paint_state(*LineLayoutAPIShim::ConstLayoutObjectFrom(
svg_root_inline_box_.GetLineLayoutItem()),
- paint_info_before_filtering);
- if (paint_state.ApplyClipMaskAndFilterIfNecessary()) {
- for (InlineBox* child = svg_root_inline_box_.FirstChild(); child;
- child = child->NextOnLine())
- child->Paint(paint_state.GetPaintInfo(), paint_offset, LayoutUnit(),
- LayoutUnit());
+ paint_info);
+ if (!paint_state.ApplyEffects())
+ return;
+ for (InlineBox* child = svg_root_inline_box_.FirstChild(); child;
+ child = child->NextOnLine()) {
+ child->Paint(paint_state.GetPaintInfo(), paint_offset, LayoutUnit(),
+ LayoutUnit());
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_root_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_root_painter.cc
index 50f5aab44c8..ccccf6411ca 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_root_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_root_painter.cc
@@ -53,7 +53,7 @@ void SVGRootPainter::PaintReplaced(const PaintInfo& paint_info,
ScopedSVGPaintState paint_state(layout_svg_root_, paint_info);
if (paint_state.GetPaintInfo().phase == PaintPhase::kForeground &&
- !paint_state.ApplyClipMaskAndFilterIfNecessary())
+ !paint_state.ApplyEffects())
return;
BoxPainter(layout_svg_root_).PaintChildren(paint_state.GetPaintInfo());
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc
index 0aea12af64b..1d744ec0f76 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/paint/svg_shape_painter.h"
-#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_shape.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
@@ -47,25 +46,22 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
layout_svg_shape_.IsShapeEmpty())
return;
- PaintInfo paint_info_before_filtering(paint_info);
-
if (SVGModelObjectPainter(layout_svg_shape_)
- .CullRectSkipsPainting(paint_info_before_filtering)) {
+ .CullRectSkipsPainting(paint_info)) {
return;
}
// Shapes cannot have children so do not call TransformCullRect.
ScopedSVGTransformState transform_state(
- paint_info_before_filtering, layout_svg_shape_,
- layout_svg_shape_.LocalSVGTransform());
+ paint_info, layout_svg_shape_, layout_svg_shape_.LocalSVGTransform());
{
- ScopedSVGPaintState paint_state(layout_svg_shape_,
- paint_info_before_filtering);
- if (paint_state.ApplyClipMaskAndFilterIfNecessary() &&
+ ScopedSVGPaintState paint_state(layout_svg_shape_, paint_info);
+ if (paint_state.ApplyEffects() &&
!DrawingRecorder::UseCachedDrawingIfPossible(
paint_state.GetPaintInfo().context, layout_svg_shape_,
paint_state.GetPaintInfo().phase)) {
- SVGModelObjectPainter::RecordHitTestData(layout_svg_shape_, paint_info);
+ SVGModelObjectPainter::RecordHitTestData(layout_svg_shape_,
+ paint_state.GetPaintInfo());
DrawingRecorder recorder(paint_state.GetPaintInfo().context,
layout_svg_shape_,
paint_state.GetPaintInfo().phase);
@@ -128,8 +124,7 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
}
break;
case PT_MARKERS:
- PaintMarkers(paint_state.GetPaintInfo(),
- layout_svg_shape_.VisualRectInLocalSVGCoordinates());
+ PaintMarkers(paint_state.GetPaintInfo());
break;
default:
NOTREACHED();
@@ -139,8 +134,7 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
}
}
- SVGModelObjectPainter(layout_svg_shape_)
- .PaintOutline(paint_info_before_filtering);
+ SVGModelObjectPainter(layout_svg_shape_).PaintOutline(paint_info);
}
class PathWithTemporaryWindingRule {
@@ -182,8 +176,7 @@ void SVGShapePainter::FillShape(GraphicsContext& context,
void SVGShapePainter::StrokeShape(GraphicsContext& context,
const PaintFlags& flags) {
- if (!layout_svg_shape_.StyleRef().SvgStyle().HasVisibleStroke())
- return;
+ DCHECK(layout_svg_shape_.StyleRef().SvgStyle().HasVisibleStroke());
switch (layout_svg_shape_.GeometryCodePath()) {
case kRectGeometryFastPath:
@@ -204,8 +197,7 @@ void SVGShapePainter::StrokeShape(GraphicsContext& context,
}
}
-void SVGShapePainter::PaintMarkers(const PaintInfo& paint_info,
- const FloatRect& bounding_box) {
+void SVGShapePainter::PaintMarkers(const PaintInfo& paint_info) {
const Vector<MarkerPosition>* marker_positions =
layout_svg_shape_.MarkerPositions();
if (!marker_positions || marker_positions->IsEmpty())
@@ -222,7 +214,7 @@ void SVGShapePainter::PaintMarkers(const PaintInfo& paint_info,
if (!marker_start && !marker_mid && !marker_end)
return;
- float stroke_width = layout_svg_shape_.StrokeWidth();
+ const float stroke_width = layout_svg_shape_.StrokeWidthForMarkerUnits();
for (const MarkerPosition& marker_position : *marker_positions) {
if (LayoutSVGResourceMarker* marker = marker_position.SelectMarker(
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.h b/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.h
index 7be80f48835..8c991f0df31 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/svg_shape_painter.h
@@ -11,7 +11,6 @@
namespace blink {
-class FloatRect;
class GraphicsContext;
class LayoutSVGResourceMarker;
class LayoutSVGShape;
@@ -31,7 +30,7 @@ class SVGShapePainter {
void FillShape(GraphicsContext&, const PaintFlags&, SkPathFillType);
void StrokeShape(GraphicsContext&, const PaintFlags&);
- void PaintMarkers(const PaintInfo&, const FloatRect& bounding_box);
+ void PaintMarkers(const PaintInfo&);
void PaintMarker(const PaintInfo&,
LayoutSVGResourceMarker&,
const MarkerPosition&,
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_text_painter.cc b/chromium/third_party/blink/renderer/core/paint/svg_text_painter.cc
index 8398f6a8f3c..d6a3ec5d4ae 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_text_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/svg_text_painter.cc
@@ -8,14 +8,14 @@
#include "third_party/blink/renderer/core/paint/block_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/scoped_svg_paint_state.h"
-#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
+#include "third_party/blink/renderer/core/paint/svg_model_object_painter.h"
namespace blink {
void SVGTextPainter::Paint(const PaintInfo& paint_info) {
if (paint_info.phase != PaintPhase::kForeground &&
paint_info.phase != PaintPhase::kForcedColorsModeBackplate &&
- paint_info.phase != PaintPhase::kSelection)
+ paint_info.phase != PaintPhase::kSelectionDragImage)
return;
PaintInfo block_info(paint_info);
@@ -28,32 +28,16 @@ void SVGTextPainter::Paint(const PaintInfo& paint_info) {
block_info, layout_svg_text_,
layout_svg_text_.LocalToSVGParentTransform());
- RecordHitTestData(paint_info);
+ if (block_info.phase == PaintPhase::kForeground)
+ SVGModelObjectPainter::RecordHitTestData(layout_svg_text_, block_info);
+
BlockPainter(layout_svg_text_).Paint(block_info);
// Paint the outlines, if any
- if (paint_info.phase == PaintPhase::kForeground) {
+ if (block_info.phase == PaintPhase::kForeground) {
block_info.phase = PaintPhase::kOutline;
BlockPainter(layout_svg_text_).Paint(block_info);
}
}
-void SVGTextPainter::RecordHitTestData(const PaintInfo& paint_info) {
- // Hit test display items are only needed for compositing. This flag is used
- // for for printing and drag images which do not need hit testing.
- if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
- return;
-
- if (paint_info.phase != PaintPhase::kForeground)
- return;
-
- auto touch_action = layout_svg_text_.EffectiveAllowedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
- return;
-
- auto rect = LayoutRect(layout_svg_text_.VisualRectInLocalSVGCoordinates());
- HitTestDisplayItem::Record(paint_info.context, layout_svg_text_,
- HitTestRect(rect, touch_action));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/svg_text_painter.h b/chromium/third_party/blink/renderer/core/paint/svg_text_painter.h
index cb4e44505c4..b05182c36c8 100644
--- a/chromium/third_party/blink/renderer/core/paint/svg_text_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/svg_text_painter.h
@@ -21,11 +21,6 @@ class SVGTextPainter {
void Paint(const PaintInfo&);
private:
- // Paint a hit test display item and record hit test data. This should be
- // called when painting the background even if there is no other painted
- // content.
- void RecordHitTestData(const PaintInfo&);
-
const LayoutSVGText& layout_svg_text_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
index 91436bbf1db..f63f5e08aec 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_painter_test.cc
@@ -35,7 +35,8 @@ TEST_P(TablePainterTest, Background) {
LayoutObject& row2 = *GetLayoutObjectByElementId("row2");
InvalidateAll(RootPaintController());
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
Paint(IntRect(0, 0, 200, 200));
EXPECT_THAT(
@@ -44,7 +45,8 @@ TEST_P(TablePainterTest, Background) {
DisplayItem::kDocumentBackground),
IsSameId(&row1, DisplayItem::kBoxDecorationBackground)));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
Paint(IntRect(0, 300, 200, 1000));
EXPECT_THAT(
@@ -77,7 +79,8 @@ TEST_P(TablePainterTest, BackgroundWithCellSpacing) {
LayoutObject& cell2 = *GetLayoutObjectByElementId("cell2");
InvalidateAll(RootPaintController());
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects cell1 and the spacing between cell1 and cell2.
Paint(IntRect(0, 200, 200, 150));
@@ -88,7 +91,8 @@ TEST_P(TablePainterTest, BackgroundWithCellSpacing) {
IsSameId(&row1, DisplayItem::kBoxDecorationBackground),
IsSameId(&cell1, DisplayItem::kBoxDecorationBackground)));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects the spacing only.
Paint(IntRect(0, 250, 100, 100));
@@ -98,7 +102,8 @@ TEST_P(TablePainterTest, BackgroundWithCellSpacing) {
DisplayItem::kDocumentBackground),
IsSameId(&row1, DisplayItem::kBoxDecorationBackground)));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects cell2 only.
Paint(IntRect(0, 350, 200, 150));
@@ -130,7 +135,8 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
LayoutObject& row = *GetLayoutObjectByElementId("row");
InvalidateAll(RootPaintController());
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects cell1 and the spacing between cell1 and cell2.
Paint(IntRect(200, 0, 200, 200));
@@ -141,7 +147,8 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
IsSameId(&row, DisplayItem::kBoxDecorationBackground),
IsSameId(&cell1, DisplayItem::kBoxDecorationBackground)));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects the spacing only.
Paint(IntRect(300, 0, 100, 100));
@@ -149,7 +156,8 @@ TEST_P(TablePainterTest, BackgroundInSelfPaintingRow) {
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
DisplayItem::kDocumentBackground)));
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects cell2 only.
Paint(IntRect(450, 0, 200, 200));
@@ -178,7 +186,8 @@ TEST_P(TablePainterTest, CollapsedBorderAndOverflow) {
const LayoutNGTableCellInterface* cell =
ToInterface<LayoutNGTableCellInterface>(cell_layout_object);
InvalidateAll(RootPaintController());
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
// Intersects the overflowing part of cell but not border box.
Paint(IntRect(0, 0, 100, 100));
diff --git a/chromium/third_party/blink/renderer/core/paint/table_row_painter.cc b/chromium/third_party/blink/renderer/core/paint/table_row_painter.cc
index 384e9a722fc..d777b775dc3 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_row_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_row_painter.cc
@@ -14,7 +14,6 @@
#include "third_party/blink/renderer/core/paint/scoped_paint_state.h"
#include "third_party/blink/renderer/core/paint/table_cell_painter.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
-#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
namespace blink {
@@ -68,34 +67,16 @@ void TableRowPainter::HandleChangedPartialPaint(
paint_result, paint_info.GetCullRect());
}
-void TableRowPainter::RecordHitTestData(const PaintInfo& paint_info,
- const PhysicalOffset& paint_offset) {
- // Hit test display items are only needed for compositing. This flag is used
- // for for printing and drag images which do not need hit testing.
- if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
- return;
-
- // If an object is not visible, it does not participate in hit testing.
- if (layout_table_row_.StyleRef().Visibility() != EVisibility::kVisible)
- return;
-
- auto touch_action = layout_table_row_.EffectiveAllowedTouchAction();
- if (touch_action == TouchAction::kTouchActionAuto)
- return;
-
- auto rect = layout_table_row_.PhysicalBorderBoxRect();
- rect.offset += paint_offset;
- HitTestDisplayItem::Record(paint_info.context, layout_table_row_,
- HitTestRect(rect.ToLayoutRect(), touch_action));
-}
-
void TableRowPainter::PaintBoxDecorationBackground(
const PaintInfo& paint_info,
const CellSpan& dirtied_columns) {
ScopedPaintState paint_state(layout_table_row_, paint_info);
const auto& local_paint_info = paint_state.GetPaintInfo();
auto paint_offset = paint_state.PaintOffset();
- RecordHitTestData(local_paint_info, paint_offset);
+ PhysicalRect paint_rect(paint_offset, layout_table_row_.Size());
+
+ BoxPainter(layout_table_row_)
+ .RecordHitTestData(local_paint_info, paint_rect, layout_table_row_);
bool has_background = layout_table_row_.StyleRef().HasBackground();
bool has_box_shadow = layout_table_row_.StyleRef().BoxShadow();
@@ -111,7 +92,6 @@ void TableRowPainter::PaintBoxDecorationBackground(
DrawingRecorder recorder(local_paint_info.context, layout_table_row_,
DisplayItem::kBoxDecorationBackground);
- PhysicalRect paint_rect(paint_offset, layout_table_row_.Size());
if (has_box_shadow) {
BoxPainterBase::PaintNormalBoxShadow(local_paint_info, paint_rect,
diff --git a/chromium/third_party/blink/renderer/core/paint/table_row_painter.h b/chromium/third_party/blink/renderer/core/paint/table_row_painter.h
index 09716046eb4..95dd74fa978 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_row_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/table_row_painter.h
@@ -13,7 +13,6 @@ namespace blink {
class CellSpan;
class LayoutTableRow;
struct PaintInfo;
-struct PhysicalOffset;
class TableRowPainter {
STACK_ALLOCATED();
@@ -31,10 +30,6 @@ class TableRowPainter {
private:
void HandleChangedPartialPaint(const PaintInfo&,
const CellSpan& dirtied_columns);
- // Paint a hit test display item and record hit test data. This should be
- // called in the background paint phase even if there is no other painted
- // content.
- void RecordHitTestData(const PaintInfo&, const PhysicalOffset& paint_offset);
const LayoutTableRow& layout_table_row_;
};
diff --git a/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc b/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc
index 6641f3e2275..374063ce4c3 100644
--- a/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/table_section_painter.cc
@@ -19,6 +19,7 @@
#include "third_party/blink/renderer/core/paint/table_row_painter.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
+#include "third_party/blink/renderer/platform/graphics/paint/scoped_display_item_fragment.h"
namespace blink {
@@ -43,11 +44,14 @@ void TableSectionPainter::Paint(const PaintInfo& paint_info) {
return;
}
+ unsigned fragment_index = 0;
for (const auto* fragment = &layout_table_section_.FirstFragment(); fragment;
fragment = fragment->NextFragment()) {
PaintInfo fragment_paint_info = paint_info;
fragment_paint_info.SetFragmentLogicalTopInFlowThread(
fragment->LogicalTopInFlowThread());
+ ScopedDisplayItemFragment scoped_display_item_fragment(
+ fragment_paint_info.context, fragment_index++);
PaintSection(fragment_paint_info);
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/text_element_timing.cc b/chromium/third_party/blink/renderer/core/paint/text_element_timing.cc
index e6e149f5129..676b3e86c54 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_element_timing.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_element_timing.cc
@@ -77,7 +77,7 @@ void TextElementTiming::OnTextObjectPainted(const TextRecord& record) {
element);
}
-void TextElementTiming::Trace(blink::Visitor* visitor) {
+void TextElementTiming::Trace(Visitor* visitor) {
Supplement<LocalDOMWindow>::Trace(visitor);
visitor->Trace(performance_);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/text_element_timing.h b/chromium/third_party/blink/renderer/core/paint/text_element_timing.h
index 664a4aed6cc..10f91076462 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_element_timing.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_element_timing.h
@@ -52,7 +52,7 @@ class CORE_EXPORT TextElementTiming final
// resolved. Dispatches PerformanceElementTiming entries to WindowPerformance.
void OnTextObjectPainted(const TextRecord&);
- void Trace(blink::Visitor* visitor) override;
+ void Trace(Visitor* visitor) override;
Member<WindowPerformance> performance_;
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_style.h b/chromium/third_party/blink/renderer/core/paint/text_paint_style.h
index e5411fdebd5..e184e7338ce 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_style.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_style.h
@@ -24,14 +24,16 @@ struct CORE_EXPORT TextPaintStyle {
float stroke_width;
const ShadowList* shadow;
- bool operator==(const TextPaintStyle& other) {
+ bool operator==(const TextPaintStyle& other) const {
return current_color == other.current_color &&
fill_color == other.fill_color &&
stroke_color == other.stroke_color &&
emphasis_mark_color == other.emphasis_mark_color &&
stroke_width == other.stroke_width && shadow == other.shadow;
}
- bool operator!=(const TextPaintStyle& other) { return !(*this == other); }
+ bool operator!=(const TextPaintStyle& other) const {
+ return !(*this == other);
+ }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
index 93c7e63670a..196fc8e59cd 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -197,7 +197,7 @@ void TextPaintTimingDetector::StopRecordingLargestTextPaint() {
records_manager_.CleanUpLargestTextPaint();
}
-void TextPaintTimingDetector::Trace(blink::Visitor* visitor) {
+void TextPaintTimingDetector::Trace(Visitor* visitor) {
visitor->Trace(records_manager_);
visitor->Trace(frame_view_);
visitor->Trace(callback_manager_);
@@ -210,7 +210,7 @@ LargestTextPaintManager::LargestTextPaintManager(
frame_view_(frame_view),
paint_timing_detector_(paint_timing_detector) {}
-void LargestTextPaintManager::Trace(blink::Visitor* visitor) {
+void LargestTextPaintManager::Trace(Visitor* visitor) {
visitor->Trace(frame_view_);
visitor->Trace(paint_timing_detector_);
}
@@ -327,7 +327,7 @@ TextRecordsManager::TextRecordsManager(
ltp_manager_.emplace(frame_view, paint_timing_detector);
}
-void TextRecordsManager::Trace(blink::Visitor* visitor) {
+void TextRecordsManager::Trace(Visitor* visitor) {
visitor->Trace(text_element_timing_);
visitor->Trace(ltp_manager_);
}
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
index 500a3003a8c..6f48bf95211 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -80,7 +80,7 @@ class CORE_EXPORT LargestTextPaintManager {
SetCachedResultInvalidated(true);
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
friend class LargestContentfulPaintCalculatorTest;
@@ -148,7 +148,7 @@ class CORE_EXPORT TextRecordsManager {
return ltp_manager_.has_value();
}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
friend class LargestContentfulPaintCalculatorTest;
@@ -216,7 +216,7 @@ class CORE_EXPORT TextPaintTimingDetector final
return records_manager_.UpdateCandidate();
}
void ReportSwapTime(base::TimeTicks timestamp);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
friend class LargestContentfulPaintCalculatorTest;
diff --git a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
index 4cdf7c03b0f..9cec3867170 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -108,7 +108,11 @@ class TextPaintTimingDetectorTest : public testing::Test {
}
void SimulateScroll() {
- GetPaintTimingDetector().NotifyScroll(ScrollType::kUserScroll);
+ GetPaintTimingDetector().NotifyScroll(mojom::blink::ScrollType::kUser);
+ }
+
+ void SimulateKeyUp() {
+ GetPaintTimingDetector().NotifyInputEvent(WebInputEvent::kKeyUp);
}
void InvokeCallback() {
@@ -145,8 +149,7 @@ class TextPaintTimingDetectorTest : public testing::Test {
void SetChildBodyInnerHTML(const String& content) {
GetChildDocument()->SetBaseURLOverride(KURL("http://test.com"));
- GetChildDocument()->body()->SetInnerHTMLFromString(content,
- ASSERT_NO_EXCEPTION);
+ GetChildDocument()->body()->setInnerHTML(content, ASSERT_NO_EXCEPTION);
child_frame_mock_callback_manager_ =
MakeGarbageCollected<MockPaintTimingCallbackManager>();
GetChildFrameTextPaintTimingDetector()->ResetCallbackManager(
@@ -155,8 +158,7 @@ class TextPaintTimingDetectorTest : public testing::Test {
}
void UpdateAllLifecyclePhases() {
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
}
// This only triggers ReportSwapTime in main frame.
@@ -236,6 +238,25 @@ class TextPaintTimingDetectorTest : public testing::Test {
Persistent<MockPaintTimingCallbackManager> child_frame_mock_callback_manager_;
};
+// Helper class to run the same test code with and without LayoutNG
+class ParameterizedTextPaintTimingDetectorTest
+ : public ::testing::WithParamInterface<bool>,
+ private ScopedLayoutNGForTest,
+ public TextPaintTimingDetectorTest {
+ public:
+ ParameterizedTextPaintTimingDetectorTest()
+ : ScopedLayoutNGForTest(GetParam()) {}
+
+ protected:
+ bool LayoutNGEnabled() const {
+ return RuntimeEnabledFeatures::LayoutNGEnabled();
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ ParameterizedTextPaintTimingDetectorTest,
+ testing::Bool());
+
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_NoText) {
SetBodyInnerHTML(R"HTML(
)HTML");
@@ -422,8 +443,7 @@ TEST_F(TextPaintTimingDetectorTest, PendingTextIsLargest) {
SetBodyInnerHTML(R"HTML(
)HTML");
AppendDivElementToBody("text");
- GetFrameView().UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetFrameView().UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
// We do not call swap-time callback here in order to not set the paint time.
EXPECT_FALSE(TextRecordOfLargestTextPaint());
}
@@ -434,12 +454,10 @@ TEST_F(TextPaintTimingDetectorTest, VisitSameNodeTwiceBeforePaintTimeIsSet) {
SetBodyInnerHTML(R"HTML(
)HTML");
Element* text = AppendDivElementToBody("text");
- GetFrameView().UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetFrameView().UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
// Change a property of the text to trigger repaint.
text->setAttribute(html_names::kStyleAttr, AtomicString("color:red;"));
- GetFrameView().UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetFrameView().UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
InvokeCallback();
EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id,
DOMNodeIds::ExistingIdForNode(text));
@@ -544,6 +562,17 @@ TEST_F(TextPaintTimingDetectorTest,
EXPECT_FALSE(GetLargestTextPaintManager());
}
+TEST_F(TextPaintTimingDetectorTest, KeepLargestTextPaintMangerAfterUserInput) {
+ SetBodyInnerHTML(R"HTML(
+ )HTML");
+ AppendDivElementToBody("text");
+ UpdateAllLifecyclePhasesAndSimulateSwapTime();
+ EXPECT_TRUE(GetLargestTextPaintManager());
+
+ SimulateKeyUp();
+ EXPECT_TRUE(GetLargestTextPaintManager());
+}
+
TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) {
SetBodyInnerHTML(R"HTML(
)HTML");
@@ -607,7 +636,7 @@ TEST_F(TextPaintTimingDetectorTest, CaptureFileUploadController) {
DOMNodeIds::ExistingIdForNode(element));
}
-TEST_F(TextPaintTimingDetectorTest, CapturingListMarkers) {
+TEST_P(ParameterizedTextPaintTimingDetectorTest, CapturingListMarkers) {
SetBodyInnerHTML(R"HTML(
<ul>
<li>List item</li>
@@ -618,7 +647,7 @@ TEST_F(TextPaintTimingDetectorTest, CapturingListMarkers) {
)HTML");
UpdateAllLifecyclePhasesAndSimulateSwapTime();
- EXPECT_EQ(CountVisibleTexts(), 2u);
+ EXPECT_EQ(CountVisibleTexts(), LayoutNGEnabled() ? 3u : 2u);
}
TEST_F(TextPaintTimingDetectorTest, CaptureSVGText) {
diff --git a/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc b/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc
index 419b89adbb9..e6b2b918f1f 100644
--- a/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc
+++ b/chromium/third_party/blink/renderer/core/paint/text_painter_base.cc
@@ -131,8 +131,7 @@ TextPaintStyle TextPainterBase::TextPaintingStyle(const Document& document,
text_style.shadow = style.TextShadow();
// Adjust text color when printing with a white background.
- DCHECK(document.Printing() == is_printing ||
- RuntimeEnabledFeatures::PrintBrowserEnabled());
+ DCHECK_EQ(document.Printing(), is_printing);
bool force_background_to_white =
BoxPainterBase::ShouldForceWhiteBackgroundForPrintEconomy(document,
style);
@@ -179,6 +178,9 @@ void TextPainterBase::DecorationsStripeIntercepts(
// pixel makes sure we're always covering. This should only be done on the
// clipping rectangle, not when computing the glyph intersects.
clip_rect.InflateY(1.0);
+
+ if (!clip_rect.IsFinite())
+ continue;
graphics_context_.ClipOut(clip_rect);
}
}
diff --git a/chromium/third_party/blink/renderer/core/paint/theme_painter.cc b/chromium/third_party/blink/renderer/core/paint/theme_painter.cc
index 8535fc1e91c..343d3275d4a 100644
--- a/chromium/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -24,15 +24,12 @@
#include "build/build_config.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
#include "third_party/blink/renderer/core/html/forms/html_data_list_options_collection.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
-#include "third_party/blink/renderer/core/html/forms/spin_button_element.h"
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
@@ -44,6 +41,7 @@
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
+#include "ui/base/ui_base_features.h"
#include "ui/native_theme/native_theme.h"
// The methods in this file are shared by all themes on every platform.
@@ -73,28 +71,12 @@ static ui::NativeTheme::ColorScheme ToNativeColorScheme(
}
}
-bool IsTemporalInput(const AtomicString& type) {
+bool IsMultipleFieldsTemporalInput(const AtomicString& type) {
+#if !defined(OS_ANDROID)
return type == input_type_names::kDate ||
type == input_type_names::kDatetimeLocal ||
type == input_type_names::kMonth || type == input_type_names::kTime ||
type == input_type_names::kWeek;
-}
-
-bool IsMenulistInput(const Node* node) {
- if (auto* input = DynamicTo<HTMLInputElement>(node)) {
-#if defined(OS_ANDROID)
- if (IsTemporalInput(input->type()))
- return true;
-#endif
- return input->type() == input_type_names::kColor &&
- input->FastHasAttribute(html_names::kListAttr);
- }
- return false;
-}
-
-bool IsMultipleFieldsTemporalInput(const AtomicString& type) {
-#if !defined(OS_ANDROID)
- return IsTemporalInput(type);
#else
return false;
#endif
@@ -106,33 +88,23 @@ ThemePainter::ThemePainter() = default;
#define COUNT_APPEARANCE(doc, feature) \
doc.CountUse(WebFeature::kCSSValueAppearance##feature##Rendered)
-#define DEPRECATE_APPEARANCE(doc, feature) \
- Deprecation::CountDeprecation( \
- doc, WebFeature::kCSSValueAppearance##feature##Rendered)
void CountAppearanceTextFieldPart(const Node* node) {
- if (!node) {
- return;
- }
- UseCounter::Count(node->GetDocument(),
- WebFeature::kCSSValueAppearanceTextFieldRendered);
- WebFeature feature =
- WebFeature::kCSSValueAppearanceTextFieldForOthersRendered;
+ DCHECK(node);
if (auto* input = DynamicTo<HTMLInputElement>(node)) {
const AtomicString& type = input->type();
if (type == input_type_names::kSearch) {
- feature = WebFeature::kCSSValueAppearanceTextFieldForSearch;
+ UseCounter::Count(node->GetDocument(),
+ WebFeature::kCSSValueAppearanceTextFieldForSearch);
} else if (input->IsTextField()) {
- feature = WebFeature::kCSSValueAppearanceTextFieldForTextField;
+ UseCounter::Count(node->GetDocument(),
+ WebFeature::kCSSValueAppearanceTextFieldForTextField);
} else if (IsMultipleFieldsTemporalInput(type)) {
- feature = WebFeature::kCSSValueAppearanceTextFieldForTemporalRendered;
+ UseCounter::Count(
+ node->GetDocument(),
+ WebFeature::kCSSValueAppearanceTextFieldForTemporalRendered);
}
}
- if (feature == WebFeature::kCSSValueAppearanceTextFieldForOthersRendered) {
- Deprecation::CountDeprecation(node->GetDocument(), feature);
- } else {
- UseCounter::Count(node->GetDocument(), feature);
- }
}
// Returns true; Needs CSS painting and/or PaintBorderOnly().
@@ -143,18 +115,16 @@ bool ThemePainter::Paint(const LayoutObject& o,
Document& doc = o.GetDocument();
const ComputedStyle& style = o.StyleRef();
ControlPart part = o.StyleRef().EffectiveAppearance();
+ // LayoutTheme::AdjustAppearanceWithElementType() ensures |node| is a
+ // non-null Element.
+ DCHECK(node);
+ DCHECK_NE(part, kNoControlPart);
if (LayoutTheme::GetTheme().ShouldUseFallbackTheme(style))
return PaintUsingFallbackTheme(node, style, paint_info, r);
- // TODO(tkent): Clean the counting code when M80 is promoted to the stable
- // channel.
- if (part == kButtonPart && node) {
- if (IsA<HTMLAnchorElement>(node)) {
- Deprecation::CountDeprecation(
- doc, WebFeature::kCSSValueAppearanceButtonForAnchor);
- COUNT_APPEARANCE(doc, ButtonForNonButton);
- } else if (IsA<HTMLButtonElement>(node)) {
+ if (part == kButtonPart) {
+ if (IsA<HTMLButtonElement>(node)) {
UseCounter::Count(doc, WebFeature::kCSSValueAppearanceButtonForButton);
} else if (IsA<HTMLInputElement>(node) &&
To<HTMLInputElement>(node)->IsTextButton()) {
@@ -166,22 +136,6 @@ bool ThemePainter::Paint(const LayoutObject& o,
To<HTMLInputElement>(node)->type() == input_type_names::kColor) {
// 'button' for input[type=color], of which default appearance is
// 'square-button', is not deprecated.
- } else {
- COUNT_APPEARANCE(doc, ButtonForNonButton);
- COUNT_APPEARANCE(doc, ButtonForOthers);
- if (IsA<HTMLSelectElement>(node) &&
- To<HTMLSelectElement>(node)->UsesMenuList()) {
- DEPRECATE_APPEARANCE(doc, ButtonForSelect);
- } else {
- const AtomicString& type =
- To<Element>(node)->getAttribute(html_names::kTypeAttr);
- // https://github.com/twbs/bootstrap/pull/29053
- if (type == "button" || type == "reset" || type == "submit") {
- DEPRECATE_APPEARANCE(doc, ButtonForBootstrapLooseSelector);
- } else {
- DEPRECATE_APPEARANCE(doc, ButtonForOthers2);
- }
- }
}
}
@@ -189,30 +143,18 @@ bool ThemePainter::Paint(const LayoutObject& o,
switch (part) {
case kCheckboxPart: {
COUNT_APPEARANCE(doc, Checkbox);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || input->type() != input_type_names::kCheckbox)
- DEPRECATE_APPEARANCE(doc, CheckboxForOthers);
return PaintCheckbox(node, o.GetDocument(), style, paint_info, r);
}
case kRadioPart: {
COUNT_APPEARANCE(doc, Radio);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || input->type() != input_type_names::kRadio)
- DEPRECATE_APPEARANCE(doc, RadioForOthers);
return PaintRadio(node, o.GetDocument(), style, paint_info, r);
}
case kPushButtonPart: {
COUNT_APPEARANCE(doc, PushButton);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || !input->IsTextButton())
- DEPRECATE_APPEARANCE(doc, PushButtonForOthers);
return PaintButton(node, o.GetDocument(), style, paint_info, r);
}
case kSquareButtonPart: {
COUNT_APPEARANCE(doc, SquareButton);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || input->type() != input_type_names::kColor)
- DEPRECATE_APPEARANCE(doc, SquareButtonForOthers);
return PaintButton(node, o.GetDocument(), style, paint_info, r);
}
case kButtonPart:
@@ -220,54 +162,31 @@ bool ThemePainter::Paint(const LayoutObject& o,
return PaintButton(node, o.GetDocument(), style, paint_info, r);
case kInnerSpinButtonPart: {
COUNT_APPEARANCE(doc, InnerSpinButton);
- if (!DynamicTo<SpinButtonElement>(node))
- DEPRECATE_APPEARANCE(doc, InnerSpinButtonForOthers);
return PaintInnerSpinButton(node, style, paint_info, r);
}
case kMenulistPart:
COUNT_APPEARANCE(doc, MenuList);
- if (!IsA<HTMLSelectElement>(node) && !IsMenulistInput(node))
- DEPRECATE_APPEARANCE(doc, MenuListForOthers);
return PaintMenuList(node, o.GetDocument(), style, paint_info, r);
case kMeterPart:
- if (node && !IsA<HTMLMeterElement>(node) &&
- !IsA<HTMLMeterElement>(node->OwnerShadowHost()))
- DEPRECATE_APPEARANCE(doc, MeterForOthers);
return true;
case kProgressBarPart:
COUNT_APPEARANCE(doc, ProgressBar);
- if (!o.IsProgress())
- DEPRECATE_APPEARANCE(doc, ProgressBarForOthers);
// Note that |-webkit-appearance: progress-bar| works only for <progress>.
return PaintProgressBar(o, paint_info, r);
case kSliderHorizontalPart: {
COUNT_APPEARANCE(doc, SliderHorizontal);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || input->type() != input_type_names::kRange)
- DEPRECATE_APPEARANCE(doc, SliderHorizontalForOthers);
return PaintSliderTrack(o, paint_info, r);
}
case kSliderVerticalPart: {
COUNT_APPEARANCE(doc, SliderVertical);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || input->type() != input_type_names::kRange)
- DEPRECATE_APPEARANCE(doc, SliderVerticalForOthers);
return PaintSliderTrack(o, paint_info, r);
}
case kSliderThumbHorizontalPart: {
COUNT_APPEARANCE(doc, SliderThumbHorizontal);
- auto* input =
- DynamicTo<HTMLInputElement>(node ? node->OwnerShadowHost() : nullptr);
- if (!input || input->type() != input_type_names::kRange)
- DEPRECATE_APPEARANCE(doc, SliderThumbHorizontalForOthers);
return PaintSliderThumb(node, style, paint_info, r);
}
case kSliderThumbVerticalPart: {
COUNT_APPEARANCE(doc, SliderThumbVertical);
- auto* input =
- DynamicTo<HTMLInputElement>(node ? node->OwnerShadowHost() : nullptr);
- if (!input || input->type() != input_type_names::kRange)
- DEPRECATE_APPEARANCE(doc, SliderThumbVerticalForOthers);
return PaintSliderThumb(node, style, paint_info, r);
}
case kMediaSliderPart:
@@ -278,53 +197,26 @@ bool ThemePainter::Paint(const LayoutObject& o,
case kMenulistButtonPart:
return true;
case kTextFieldPart:
- if (!RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (!features::IsFormControlsRefreshEnabled()) {
return true;
}
CountAppearanceTextFieldPart(node);
return PaintTextField(node, style, paint_info, r);
case kTextAreaPart:
- if (!RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (!features::IsFormControlsRefreshEnabled()) {
return true;
}
- if (node) {
- const auto& doc = node->GetDocument();
- COUNT_APPEARANCE(doc, TextArea);
- if (!IsA<HTMLTextAreaElement>(node))
- DEPRECATE_APPEARANCE(doc, TextAreaForOthers);
- }
+ COUNT_APPEARANCE(doc, TextArea);
return PaintTextArea(node, style, paint_info, r);
case kSearchFieldPart: {
COUNT_APPEARANCE(doc, SearchField);
- auto* input = DynamicTo<HTMLInputElement>(node);
- if (!input || input->type() != input_type_names::kSearch)
- DEPRECATE_APPEARANCE(doc, SearchFieldForOthers);
return PaintSearchField(node, style, paint_info, r);
}
case kSearchFieldCancelButtonPart: {
COUNT_APPEARANCE(doc, SearchCancel);
- auto* element = DynamicTo<Element>(node);
- if (!element || !element->OwnerShadowHost()) {
- COUNT_APPEARANCE(doc, SearchCancelForOthers);
- DEPRECATE_APPEARANCE(doc, SearchCancelForOthers2);
- } else {
- const AtomicString& shadow_id =
- element->FastGetAttribute(html_names::kIdAttr);
- if (shadow_id == shadow_element_names::SearchClearButton()) {
- // Count nothing.
- } else if (shadow_id == shadow_element_names::ClearButton()) {
- COUNT_APPEARANCE(doc, SearchCancelForOthers);
- } else {
- COUNT_APPEARANCE(doc, SearchCancelForOthers);
- DEPRECATE_APPEARANCE(doc, SearchCancelForOthers2);
- }
- }
return PaintSearchFieldCancelButton(o, paint_info, r);
}
case kListboxPart:
- if (!IsA<HTMLSelectElement>(node) ||
- To<HTMLSelectElement>(node)->UsesMenuList())
- DEPRECATE_APPEARANCE(doc, ListboxForOthers);
return true;
default:
break;
@@ -342,21 +234,16 @@ bool ThemePainter::PaintBorderOnly(const Node* node,
// Call the appropriate paint method based off the appearance value.
switch (style.EffectiveAppearance()) {
case kTextFieldPart:
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (features::IsFormControlsRefreshEnabled()) {
return false;
}
CountAppearanceTextFieldPart(node);
return PaintTextField(node, style, paint_info, r);
case kTextAreaPart:
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (features::IsFormControlsRefreshEnabled()) {
return false;
}
- if (node) {
- const auto& doc = node->GetDocument();
- COUNT_APPEARANCE(doc, TextArea);
- if (!IsA<HTMLTextAreaElement>(node))
- DEPRECATE_APPEARANCE(doc, TextAreaForOthers);
- }
+ COUNT_APPEARANCE(node->GetDocument(), TextArea);
return PaintTextArea(node, style, paint_info, r);
case kMenulistButtonPart:
case kSearchFieldPart:
@@ -378,11 +265,9 @@ bool ThemePainter::PaintBorderOnly(const Node* node,
// Supported appearance values don't need CSS border painting.
return false;
default:
- if (node) {
- UseCounter::Count(
- node->GetDocument(),
- WebFeature::kCSSValueAppearanceNoImplementationSkipBorder);
- }
+ UseCounter::Count(
+ node->GetDocument(),
+ WebFeature::kCSSValueAppearanceNoImplementationSkipBorder);
// TODO(tkent): Should do CSS border painting for non-supported
// appearance values.
return false;
@@ -400,8 +285,6 @@ bool ThemePainter::PaintDecorations(const Node* node,
switch (style.EffectiveAppearance()) {
case kMenulistButtonPart:
COUNT_APPEARANCE(document, MenuListButton);
- if (!IsA<HTMLSelectElement>(node) && !IsMenulistInput(node))
- DEPRECATE_APPEARANCE(document, MenuListButtonForOthers);
return PaintMenuListButton(node, document, style, paint_info, r);
case kTextFieldPart:
case kTextAreaPart:
diff --git a/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc b/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc
index cc25ef54157..9da24a1c670 100644
--- a/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc
+++ b/chromium/third_party/blink/renderer/core/paint/theme_painter_default.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
+#include "ui/base/ui_base_features.h"
namespace blink {
@@ -151,8 +152,7 @@ bool ThemePainterDefault::PaintCheckbox(const Node* node,
extra_params.button.zoom = zoom_level;
GraphicsContextStateSaver state_saver(paint_info.context, false);
IntRect unzoomed_rect = rect;
- if (zoom_level != 1 &&
- !RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (zoom_level != 1 && !features::IsFormControlsRefreshEnabled()) {
state_saver.Save();
unzoomed_rect.SetWidth(unzoomed_rect.Width() / zoom_level);
unzoomed_rect.SetHeight(unzoomed_rect.Height() / zoom_level);
@@ -227,12 +227,15 @@ bool ThemePainterDefault::PaintTextField(const Node* node,
WebThemeEngine::ExtraParams extra_params;
extra_params.text_field.is_text_area = part == kTextAreaPart;
extra_params.text_field.is_listbox = part == kListboxPart;
+ extra_params.text_field.has_border = true;
cc::PaintCanvas* canvas = paint_info.context.Canvas();
Color background_color =
style.VisitedDependentColor(GetCSSPropertyBackgroundColor());
extra_params.text_field.background_color = background_color.Rgb();
+ extra_params.text_field.auto_complete_active =
+ DynamicTo<HTMLFormControlElement>(node)->IsAutofilled();
Platform::Current()->ThemeEngine()->Paint(
canvas, WebThemeEngine::kPartTextField, GetWebThemeState(node),
@@ -307,9 +310,8 @@ void ThemePainterDefault::SetupMenuListArrow(
theme_.ClampedMenuListArrowPaddingSize(document.GetFrame(), style);
float arrow_scale_factor = arrow_box_width / theme_.MenuListArrowWidthInDIP();
// TODO(tkent): This should be 7.0 to match scroll bar buttons.
- float arrow_size =
- (RuntimeEnabledFeatures::FormControlsRefreshEnabled() ? 8.0 : 6.0) *
- arrow_scale_factor;
+ float arrow_size = (features::IsFormControlsRefreshEnabled() ? 8.0 : 6.0) *
+ arrow_scale_factor;
// Put the arrow at the center of paddingForArrow area.
// |arrowX| is the left position for Aura theme engine.
extra_params.menu_list.arrow_x =
@@ -336,8 +338,7 @@ bool ThemePainterDefault::PaintSliderTrack(const LayoutObject& o,
extra_params.slider.zoom = zoom_level;
GraphicsContextStateSaver state_saver(i.context, false);
IntRect unzoomed_rect = rect;
- if (zoom_level != 1 &&
- !RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (zoom_level != 1 && !features::IsFormControlsRefreshEnabled()) {
state_saver.Save();
unzoomed_rect.SetWidth(unzoomed_rect.Width() / zoom_level);
unzoomed_rect.SetHeight(unzoomed_rect.Height() / zoom_level);
@@ -357,7 +358,7 @@ bool ThemePainterDefault::PaintSliderTrack(const LayoutObject& o,
LayoutBox* thumb = thumb_element ? thumb_element->GetLayoutBox() : nullptr;
if (thumb) {
IntRect thumb_rect = PixelSnappedIntRect(thumb->FrameRect());
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (features::IsFormControlsRefreshEnabled()) {
extra_params.slider.thumb_x = thumb_rect.X();
extra_params.slider.thumb_y = thumb_rect.Y();
} else {
@@ -387,8 +388,7 @@ bool ThemePainterDefault::PaintSliderThumb(const Node* node,
extra_params.slider.zoom = zoom_level;
GraphicsContextStateSaver state_saver(paint_info.context, false);
IntRect unzoomed_rect = rect;
- if (zoom_level != 1 &&
- !RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (zoom_level != 1 && !features::IsFormControlsRefreshEnabled()) {
state_saver.Save();
unzoomed_rect.SetWidth(unzoomed_rect.Width() / zoom_level);
unzoomed_rect.SetHeight(unzoomed_rect.Height() / zoom_level);
diff --git a/chromium/third_party/blink/renderer/core/paint/video_painter.cc b/chromium/third_party/blink/renderer/core/paint/video_painter.cc
index 27c37014ec4..b15d3ec197a 100644
--- a/chromium/third_party/blink/renderer/core/paint/video_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/video_painter.cc
@@ -41,6 +41,11 @@ void VideoPainter::PaintReplaced(const PaintInfo& paint_info,
PhysicalRect content_box_rect = layout_video_.PhysicalContentBoxRect();
content_box_rect.Move(paint_offset);
+ if (context.IsPaintingPreview()) {
+ context.SetURLForRect(layout_video_.GetDocument().Url(),
+ snapped_replaced_rect);
+ }
+
// Since we may have changed the location of the replaced content, we need to
// notify PaintArtifactCompositor.
if (layout_video_.GetFrameView())
diff --git a/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
index 3e03db3ede0..954e9b4fb13 100644
--- a/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/video_painter_test.cc
@@ -4,9 +4,13 @@
#include "third_party/blink/renderer/core/paint/video_painter.h"
+#include "base/unguessable_token.h"
#include "cc/layers/layer.h"
+#include "components/paint_preview/common/paint_preview_tracker.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_size.h"
+#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
#include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
@@ -86,17 +90,87 @@ TEST_F(VideoPainterTestForCAP, VideoLayerAppearsInLayerTree) {
// Fetch the layer associated with the <video>, and check that it was
// correctly configured in the layer tree.
- HTMLMediaElement* element =
- ToHTMLMediaElement(GetDocument().body()->firstChild());
+ auto* element = To<HTMLMediaElement>(GetDocument().body()->firstChild());
StubWebMediaPlayer* player =
static_cast<StubWebMediaPlayer*>(element->GetWebMediaPlayer());
const cc::Layer* layer = player->GetCcLayer();
ASSERT_TRUE(layer);
EXPECT_TRUE(HasLayerAttached(*layer));
- // The layer bounds reflects the aspectn ratio and object-fit of the video.
- EXPECT_EQ(gfx::Vector2dF(8, 83), layer->offset_to_transform_parent());
+ // The layer bounds reflects the aspect ratio and object-fit of the video.
+ EXPECT_EQ(gfx::Vector2dF(0, 75), layer->offset_to_transform_parent());
EXPECT_EQ(gfx::Size(300, 150), layer->bounds());
}
+class VideoPaintPreviewTest : public testing::Test,
+ public PaintTestConfigurations {
+ public:
+ void SetUp() override {
+ web_view_helper_.Initialize();
+
+ WebLocalFrameImpl& frame_impl = GetLocalMainFrame();
+ frame_impl.ViewImpl()->MainFrameWidget()->Resize(WebSize(bounds().size()));
+
+ frame_test_helpers::LoadFrame(&GetLocalMainFrame(), "about:blank");
+ GetDocument().View()->SetParentVisible(true);
+ GetDocument().View()->SetSelfVisible(true);
+ }
+
+ void SetBodyInnerHTML(const std::string& content) {
+ frame_test_helpers::LoadHTMLString(&GetLocalMainFrame(), content,
+ KURL("http://test.com"));
+ }
+
+ Document& GetDocument() { return *GetFrame()->GetDocument(); }
+
+ WebLocalFrameImpl& GetLocalMainFrame() {
+ return *web_view_helper_.LocalMainFrame();
+ }
+
+ const gfx::Rect& bounds() { return bounds_; }
+
+ private:
+ LocalFrame* GetFrame() { return GetLocalMainFrame().GetFrame(); }
+
+ frame_test_helpers::WebViewHelper web_view_helper_;
+ gfx::Rect bounds_ = {0, 0, 640, 480};
+};
+
+INSTANTIATE_PAINT_TEST_SUITE_P(VideoPaintPreviewTest);
+
+TEST_P(VideoPaintPreviewTest, URLIsRecordedWhenPaintingPreview) {
+ // Insert a <video> and allow it to begin loading. The image was taken from
+ // the RFC for the data URI scheme https://tools.ietf.org/html/rfc2397.
+ SetBodyInnerHTML(R"HTML(
+ <style>body{margin:0}</style>
+ <video width=300 height=300 src="test.ogv" poster="data:image/gif;base64,R0
+ lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yq
+ mCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP
+ 5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGe
+ jmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1O
+ IcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7"
+ controls>
+ )HTML");
+ test::RunPendingTasks();
+
+ auto token = base::UnguessableToken::Create();
+ const base::UnguessableToken embedding_token =
+ base::UnguessableToken::Create();
+ const bool is_main_frame = true;
+
+ cc::PaintRecorder recorder;
+ paint_preview::PaintPreviewTracker tracker(token, embedding_token,
+ is_main_frame);
+ cc::PaintCanvas* canvas =
+ recorder.beginRecording(bounds().width(), bounds().height());
+ canvas->SetPaintPreviewTracker(&tracker);
+
+ EXPECT_EQ(0lu, tracker.GetLinks().size());
+ GetLocalMainFrame().CapturePaintPreview(WebRect(bounds()), canvas);
+
+ ASSERT_EQ(1lu, tracker.GetLinks().size());
+ EXPECT_EQ("http://test.com/", tracker.GetLinks()[0].url);
+ EXPECT_EQ(gfx::Rect(300, 300), tracker.GetLinks()[0].rect);
+}
+
} // namespace
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/view_painter.cc b/chromium/third_party/blink/renderer/core/paint/view_painter.cc
index 2b8c3cc46eb..1ce2481e0a0 100644
--- a/chromium/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/view_painter.cc
@@ -33,6 +33,38 @@ void ViewPainter::Paint(const PaintInfo& paint_info) {
BlockPainter(layout_view_).Paint(paint_info);
}
+// Behind the root element of the main frame of the page, there is an infinite
+// canvas. This is by default white, but it can be overridden by
+// BaseBackgroundColor on the LocalFrameView.
+// https://drafts.fxtf.org/compositing/#rootgroup
+void ViewPainter::PaintRootGroup(const PaintInfo& paint_info,
+ const IntRect& pixel_snapped_background_rect,
+ const Document& document,
+ const DisplayItemClient& client,
+ const PropertyTreeState& state) {
+ if (!document.IsInMainFrame())
+ return;
+ bool should_clear_canvas =
+ document.GetSettings() &&
+ document.GetSettings()->GetShouldClearDocumentBackground();
+
+ Color base_background_color =
+ layout_view_.GetFrameView()->BaseBackgroundColor();
+
+ ScopedPaintChunkProperties frame_view_background_state(
+ paint_info.context.GetPaintController(), state, client,
+ DisplayItem::kDocumentRootBackdrop);
+ GraphicsContext& context = paint_info.context;
+ if (!DrawingRecorder::UseCachedDrawingIfPossible(
+ context, client, DisplayItem::kDocumentRootBackdrop)) {
+ DrawingRecorder recorder(context, client,
+ DisplayItem::kDocumentRootBackdrop);
+ context.FillRect(
+ pixel_snapped_background_rect, base_background_color,
+ should_clear_canvas ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
+ }
+}
+
void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
if (layout_view_.StyleRef().Visibility() != EVisibility::kVisible)
return;
@@ -57,7 +89,6 @@ void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
const DisplayItemClient* background_client = &layout_view_;
- base::Optional<ScopedPaintChunkProperties> scoped_scroll_property;
bool painting_scrolling_background =
BoxDecorationData::IsPaintingScrollingBackground(paint_info,
layout_view_);
@@ -71,20 +102,84 @@ void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
background_rect.Unite(document_rect);
background_client = &layout_view_.GetScrollableArea()
->GetScrollingBackgroundDisplayItemClient();
- scoped_scroll_property.emplace(
- paint_info.context.GetPaintController(),
- layout_view_.FirstFragment().ContentsProperties(), *background_client,
- DisplayItem::kDocumentBackground);
}
- if (layout_view_.HasBoxDecorationBackground()) {
- PaintBoxDecorationBackgroundInternal(
- paint_info, PixelSnappedIntRect(background_rect), *background_client);
+ IntRect pixel_snapped_background_rect(PixelSnappedIntRect(background_rect));
+
+ const Document& document = layout_view_.GetDocument();
+
+ PropertyTreeState root_element_background_painting_state =
+ layout_view_.FirstFragment().ContentsProperties();
+
+ base::Optional<ScopedPaintChunkProperties> scoped_properties;
+
+ bool painted_separate_backdrop = false;
+ bool painted_separate_effect = false;
+
+ bool should_apply_root_background_behavior =
+ layout_view_.GetDocument().IsHTMLDocument() ||
+ layout_view_.GetDocument().IsXHTMLDocument();
+
+ bool should_paint_background = !paint_info.SkipRootBackground() &&
+ layout_view_.HasBoxDecorationBackground();
+
+ LayoutObject* root_object = nullptr;
+ if (layout_view_.GetDocument().documentElement()) {
+ root_object =
+ layout_view_.GetDocument().documentElement()->GetLayoutObject();
+ }
+
+ // For HTML and XHTML documents, the root element may paint in a different
+ // clip, effect or transform state than the LayoutView. For
+ // example, the HTML element may have a clip-path, filter, blend-mode,
+ // opacity or transform.
+ //
+ // In these cases, we should paint the background of the root element in
+ // its LocalBorderBoxProperties() state, as part of the Root Element Group
+ // [1]. In addition, for the main frame of the page, we also need to paint the
+ // default backdrop color in the Root Group [2]. The Root Group paints in
+ // the scrolling space of the LayoutView (i.e. its ContentsProperties()).
+ //
+ // [1] https://drafts.fxtf.org/compositing/#pagebackdrop
+ // [2] https://drafts.fxtf.org/compositing/#rootgroup
+ if (should_paint_background && painting_scrolling_background &&
+ should_apply_root_background_behavior && root_object) {
+ const PropertyTreeState& document_element_state =
+ root_object->FirstFragment().LocalBorderBoxProperties();
+
+ // As an optimization, only paint a separate PaintChunk for the
+ // root group if its property tree state differs from root element
+ // group's. Otherwise we can usually avoid both a separate
+ // PaintChunk and a BeginLayer/EndLayer.
+ if (document_element_state != root_element_background_painting_state) {
+ if (&document_element_state.Effect() !=
+ &root_element_background_painting_state.Effect())
+ painted_separate_effect = true;
+
+ root_element_background_painting_state = document_element_state;
+ PaintRootGroup(paint_info, pixel_snapped_background_rect, document,
+ *background_client,
+ layout_view_.FirstFragment().ContentsProperties());
+ painted_separate_backdrop = true;
+ }
+ }
+
+ if (painting_scrolling_background) {
+ scoped_properties.emplace(paint_info.context.GetPaintController(),
+ root_element_background_painting_state,
+ *background_client,
+ DisplayItem::kDocumentBackground);
+ }
+
+ if (should_paint_background) {
+ PaintRootElementGroup(paint_info, pixel_snapped_background_rect,
+ *background_client, painted_separate_backdrop,
+ painted_separate_effect);
}
if (has_touch_action_rect) {
BoxPainter(layout_view_)
.RecordHitTestData(paint_info,
- PhysicalRect(PixelSnappedIntRect(background_rect)),
+ PhysicalRect(pixel_snapped_background_rect),
*background_client);
}
@@ -119,22 +214,23 @@ void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
// View background painting is special in the following ways:
// 1. The view paints background for the root element, the background
// positioning respects the positioning and transformation of the root
-// element.
+// element. However, this method assumes that there is already an
+// PaintChunk being recorded with the LocalBorderBoxProperties of the
+// root element. Therefore the transform of the root element
+// are applied via PaintChunksToCcLayer, and not via the display list of the
+// PaintChunk itself.
// 2. CSS background-clip is ignored, the background layers always expand to
-// cover the whole canvas. None of the stacking context effects (except
-// transformation) on the root element affects the background.
+// cover the whole canvas.
// 3. The main frame is also responsible for painting the user-agent-defined
// base background color. Conceptually it should be painted by the embedder
// but painting it here allows culling and pre-blending optimization when
// possible.
-void ViewPainter::PaintBoxDecorationBackgroundInternal(
+void ViewPainter::PaintRootElementGroup(
const PaintInfo& paint_info,
- const IntRect& background_rect,
- const DisplayItemClient& background_client) {
- // TODO(pdr): Can this check be removed? It is not hit in any test.
- if (paint_info.SkipRootBackground())
- return;
-
+ const IntRect& pixel_snapped_background_rect,
+ const DisplayItemClient& background_client,
+ bool painted_separate_backdrop,
+ bool painted_separate_effect) {
GraphicsContext& context = paint_info.context;
if (DrawingRecorder::UseCachedDrawingIfPossible(
context, background_client, DisplayItem::kDocumentBackground)) {
@@ -149,8 +245,9 @@ void ViewPainter::PaintBoxDecorationBackgroundInternal(
(frame_view.BaseBackgroundColor().Alpha() > 0);
Color base_background_color =
paints_base_background ? frame_view.BaseBackgroundColor() : Color();
- Color root_background_color = layout_view_.StyleRef().VisitedDependentColor(
- GetCSSPropertyBackgroundColor());
+ Color root_element_background_color =
+ layout_view_.StyleRef().VisitedDependentColor(
+ GetCSSPropertyBackgroundColor());
const LayoutObject* root_object =
document.documentElement() ? document.documentElement()->GetLayoutObject()
: nullptr;
@@ -162,9 +259,11 @@ void ViewPainter::PaintBoxDecorationBackgroundInternal(
if (force_background_to_white) {
// If for any reason the view background is not transparent, paint white
// instead, otherwise keep transparent as is.
- if (paints_base_background || root_background_color.Alpha() ||
- layout_view_.StyleRef().BackgroundLayers().AnyLayerHasImage())
- context.FillRect(background_rect, Color::kWhite, SkBlendMode::kSrc);
+ if (paints_base_background || root_element_background_color.Alpha() ||
+ layout_view_.StyleRef().BackgroundLayers().AnyLayerHasImage()) {
+ context.FillRect(pixel_snapped_background_rect, Color::kWhite,
+ SkBlendMode::kSrc);
+ }
return;
}
@@ -177,49 +276,39 @@ void ViewPainter::PaintBoxDecorationBackgroundInternal(
// transform on the document rect to get to the root element space.
// Local / scroll positioned background images will be painted into scrolling
// contents layer with root layer scrolling. Therefore we need to switch both
- // the background_rect and context to documentElement visual space.
+ // the pixel_snapped_background_rect and context to documentElement visual
+ // space.
bool background_renderable = true;
- TransformationMatrix transform;
- IntRect paint_rect = background_rect;
+ bool root_element_has_transform = false;
+ IntRect paint_rect = pixel_snapped_background_rect;
if (!root_object || !root_object->IsBox()) {
background_renderable = false;
- } else if (root_object->HasLayer()) {
- if (BoxDecorationData::IsPaintingScrollingBackground(paint_info,
- layout_view_)) {
- transform.Translate(
- layout_view_.PixelSnappedScrolledContentOffset().Width(),
- layout_view_.PixelSnappedScrolledContentOffset().Height());
- }
- const PaintLayer& root_layer =
- *ToLayoutBoxModelObject(root_object)->Layer();
- PhysicalOffset offset;
- root_layer.ConvertToLayerCoords(nullptr, offset);
- transform.Translate(offset.left, offset.top);
- transform.Multiply(
- root_layer.RenderableTransform(paint_info.GetGlobalPaintFlags()));
-
- if (!transform.IsInvertible()) {
+ } else {
+ root_element_has_transform = root_object->StyleRef().HasTransform();
+ TransformationMatrix transform;
+ root_object->GetTransformFromContainer(root_object->View(),
+ PhysicalOffset(), transform);
+ if (!transform.IsInvertible())
background_renderable = false;
- } else {
- bool is_clamped;
- paint_rect = transform.Inverse()
- .ProjectQuad(FloatQuad(background_rect), &is_clamped)
- .EnclosingBoundingBox();
- background_renderable = !is_clamped;
- }
+ else
+ paint_rect = transform.Inverse().MapRect(pixel_snapped_background_rect);
}
bool should_clear_canvas =
paints_base_background &&
(document.GetSettings() &&
document.GetSettings()->GetShouldClearDocumentBackground());
+
if (!background_renderable) {
- if (base_background_color.Alpha()) {
- context.FillRect(
- background_rect, base_background_color,
- should_clear_canvas ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
- } else if (should_clear_canvas) {
- context.FillRect(background_rect, Color(), SkBlendMode::kClear);
+ if (!painted_separate_backdrop) {
+ if (base_background_color.Alpha()) {
+ context.FillRect(
+ pixel_snapped_background_rect, base_background_color,
+ should_clear_canvas ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
+ } else if (should_clear_canvas) {
+ context.FillRect(pixel_snapped_background_rect, Color(),
+ SkBlendMode::kClear);
+ }
}
return;
}
@@ -231,21 +320,30 @@ void ViewPainter::PaintBoxDecorationBackgroundInternal(
reversed_paint_list, layout_view_.StyleRef().BackgroundLayers());
DCHECK(reversed_paint_list.size());
- // If the root background color is opaque, isolation group can be skipped
- // because the canvas
- // will be cleared by root background color.
- if (!root_background_color.HasAlpha())
- should_draw_background_in_separate_buffer = false;
-
- // We are going to clear the canvas with transparent pixels, isolation group
- // can be skipped.
- if (!base_background_color.Alpha() && should_clear_canvas)
- should_draw_background_in_separate_buffer = false;
+ if (painted_separate_effect) {
+ should_draw_background_in_separate_buffer = true;
+ } else {
+ // If the root background color is opaque, isolation group can be skipped
+ // because the canvas
+ // will be cleared by root background color.
+ if (!root_element_background_color.HasAlpha())
+ should_draw_background_in_separate_buffer = false;
+
+ // We are going to clear the canvas with transparent pixels, isolation group
+ // can be skipped.
+ if (!base_background_color.Alpha() && should_clear_canvas)
+ should_draw_background_in_separate_buffer = false;
+ }
- if (should_draw_background_in_separate_buffer) {
+ // Only use BeginLayer if not only we should draw in a separate buffer, but
+ // we also didn't paint a separate backdrop. Separate backdrops are always
+ // painted when there is any effect on the root element, such as a blend
+ // mode. An extra BeginLayer will result in incorrect blend isolation if
+ // it is added on top of any effect on the root element.
+ if (should_draw_background_in_separate_buffer && !painted_separate_effect) {
if (base_background_color.Alpha()) {
context.FillRect(
- background_rect, base_background_color,
+ paint_rect, base_background_color,
should_clear_canvas ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
}
context.BeginLayer();
@@ -253,48 +351,38 @@ void ViewPainter::PaintBoxDecorationBackgroundInternal(
Color combined_background_color =
should_draw_background_in_separate_buffer
- ? root_background_color
- : base_background_color.Blend(root_background_color);
+ ? root_element_background_color
+ : base_background_color.Blend(root_element_background_color);
if (combined_background_color != frame_view.BaseBackgroundColor())
context.GetPaintController().SetFirstPainted();
if (combined_background_color.Alpha()) {
- if (!combined_background_color.HasAlpha() &&
- RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
- recorder.SetKnownToBeOpaque();
context.FillRect(
- background_rect, combined_background_color,
+ paint_rect, combined_background_color,
(should_draw_background_in_separate_buffer || should_clear_canvas)
? SkBlendMode::kSrc
: SkBlendMode::kSrcOver);
} else if (should_clear_canvas &&
!should_draw_background_in_separate_buffer) {
- context.FillRect(background_rect, Color(), SkBlendMode::kClear);
+ context.FillRect(paint_rect, Color(), SkBlendMode::kClear);
}
- BackgroundImageGeometry geometry(layout_view_);
+ BackgroundImageGeometry geometry(layout_view_, root_element_has_transform);
BoxModelObjectPainter box_model_painter(layout_view_);
for (const auto* fill_layer : base::Reversed(reversed_paint_list)) {
DCHECK(fill_layer->Clip() == EFillBox::kBorder);
- if (BackgroundImageGeometry::ShouldUseFixedAttachment(*fill_layer)) {
- box_model_painter.PaintFillLayer(paint_info, Color(), *fill_layer,
- PhysicalRect(background_rect),
- kBackgroundBleedNone, geometry);
- } else {
- context.Save();
- // TODO(trchen): We should be able to handle 3D-transformed root
- // background with slimming paint by using transform display items.
- context.ConcatCTM(transform.ToAffineTransform());
- box_model_painter.PaintFillLayer(paint_info, Color(), *fill_layer,
- PhysicalRect(paint_rect),
- kBackgroundBleedNone, geometry);
- context.Restore();
- }
+ PhysicalRect painting_rect(paint_rect);
+ if (!BackgroundImageGeometry::ShouldUseFixedAttachment(*fill_layer))
+ painting_rect.Move(root_object->FirstFragment().PaintOffset());
+
+ box_model_painter.PaintFillLayer(paint_info, Color(), *fill_layer,
+ painting_rect, kBackgroundBleedNone,
+ geometry);
}
- if (should_draw_background_in_separate_buffer)
+ if (should_draw_background_in_separate_buffer && !painted_separate_effect)
context.EndLayer();
}
diff --git a/chromium/third_party/blink/renderer/core/paint/view_painter.h b/chromium/third_party/blink/renderer/core/paint/view_painter.h
index 652ffd6cb9e..921839b76f8 100644
--- a/chromium/third_party/blink/renderer/core/paint/view_painter.h
+++ b/chromium/third_party/blink/renderer/core/paint/view_painter.h
@@ -11,8 +11,10 @@ namespace blink {
struct PaintInfo;
class DisplayItemClient;
+class Document;
class IntRect;
class LayoutView;
+class PropertyTreeState;
class ViewPainter {
STACK_ALLOCATED();
@@ -26,10 +28,17 @@ class ViewPainter {
private:
const LayoutView& layout_view_;
- void PaintBoxDecorationBackgroundInternal(
- const PaintInfo&,
- const IntRect& background_rect,
- const DisplayItemClient& background_client);
+ void PaintRootElementGroup(const PaintInfo&,
+ const IntRect& pixel_snapped_background_rect,
+ const DisplayItemClient& background_client,
+ bool painted_separate_backdrop,
+ bool painted_separate_effect);
+
+ void PaintRootGroup(const PaintInfo& paint_info,
+ const IntRect& pixel_snapped_background_rect,
+ const Document&,
+ const DisplayItemClient& background_client,
+ const PropertyTreeState& state);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc b/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc
index 60d2ceb43db..e26b77a20d5 100644
--- a/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc
+++ b/chromium/third_party/blink/renderer/core/paint/view_painter_test.cc
@@ -9,20 +9,19 @@
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
-#include "third_party/blink/renderer/platform/graphics/paint/scroll_hit_test_display_item.h"
using testing::ElementsAre;
namespace blink {
-class ViewPainterTest : public PaintControllerPaintTest {
+class ViewPainterFixedBackgroundTest : public PaintControllerPaintTest {
protected:
void RunFixedBackgroundTest(bool prefer_compositing_to_lcd_text);
};
-INSTANTIATE_PAINT_TEST_SUITE_P(ViewPainterTest);
+INSTANTIATE_PAINT_TEST_SUITE_P(ViewPainterFixedBackgroundTest);
-void ViewPainterTest::RunFixedBackgroundTest(
+void ViewPainterFixedBackgroundTest::RunFixedBackgroundTest(
bool prefer_compositing_to_lcd_text) {
if (prefer_compositing_to_lcd_text) {
Settings* settings = GetDocument().GetFrame()->GetSettings();
@@ -45,27 +44,19 @@ void ViewPainterTest::RunFixedBackgroundTest(
ScrollableArea* layout_viewport = frame_view->LayoutViewport();
ScrollOffset scroll_offset(200, 150);
- layout_viewport->SetScrollOffset(scroll_offset, kUserScroll);
- frame_view->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ layout_viewport->SetScrollOffset(scroll_offset,
+ mojom::blink::ScrollType::kUser);
+ frame_view->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
const DisplayItem* background_display_item = nullptr;
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
const auto& display_items = RootPaintController().GetDisplayItemList();
- if (prefer_compositing_to_lcd_text) {
- EXPECT_THAT(
- display_items,
- ElementsAre(IsSameId(&GetLayoutView(), kDocumentBackgroundType),
- IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest)));
- background_display_item = &display_items[0];
- } else {
- EXPECT_THAT(
- display_items,
- ElementsAre(IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
- IsSameId(&ViewScrollingBackgroundClient(),
- kDocumentBackgroundType)));
- background_display_item = &display_items[1];
- }
+ const auto& background_client = prefer_compositing_to_lcd_text
+ ? GetLayoutView()
+ : ViewScrollingBackgroundClient();
+ EXPECT_THAT(display_items, ElementsAre(IsSameId(&background_client,
+ kDocumentBackgroundType)));
+ background_display_item = &display_items[0];
} else {
// If we prefer compositing to LCD text, the fixed background should go in a
// different layer from the scrolling content; otherwise, it should go in
@@ -108,66 +99,65 @@ void ViewPainterTest::RunFixedBackgroundTest(
}
}
-TEST_P(ViewPainterTest, DocumentFixedBackgroundLowDPI) {
+TEST_P(ViewPainterFixedBackgroundTest, DocumentFixedBackgroundLowDPI) {
RunFixedBackgroundTest(false);
}
-TEST_P(ViewPainterTest, DocumentFixedBackgroundHighDPI) {
+TEST_P(ViewPainterFixedBackgroundTest, DocumentFixedBackgroundHighDPI) {
RunFixedBackgroundTest(true);
}
-using ViewPainterScrollHitTestTest = PaintControllerPaintTest;
+using ViewPainterTest = PaintControllerPaintTest;
-INSTANTIATE_SCROLL_HIT_TEST_SUITE_P(ViewPainterScrollHitTestTest);
+INSTANTIATE_PAINT_TEST_SUITE_P(ViewPainterTest);
-TEST_P(ViewPainterScrollHitTestTest, DocumentBackgroundWithScroll) {
+TEST_P(ViewPainterTest, DocumentBackgroundWithScroll) {
SetBodyInnerHTML(R"HTML(
<style>::-webkit-scrollbar { display: none }</style>
<div style='height: 5000px'></div>
)HTML");
+ const auto& scrolling_contents_properties =
+ GetLayoutView().FirstFragment().ContentsProperties();
+
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+ EXPECT_THAT(RootPaintController().GetDisplayItemList(),
+ ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType)));
+ HitTestData scroll_hit_test_data;
+ scroll_hit_test_data.scroll_translation =
+ &scrolling_contents_properties.Transform();
+ scroll_hit_test_data.scroll_hit_test_rect = IntRect(0, 0, 800, 600);
// The scroll hit test should be before the scrolled contents to ensure the
// hit test does not prevent the background squashing with the scrolling
// contents.
EXPECT_THAT(
- RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&GetLayoutView(), DisplayItem::kScrollHitTest),
- IsSameId(&ViewScrollingBackgroundClient(),
- kDocumentBackgroundType)));
- HitTestData scroll_hit_test_data;
- const auto& scrolling_contents_properties =
- GetLayoutView().FirstFragment().ContentsProperties();
- scroll_hit_test_data.SetScrollHitTest(
- &scrolling_contents_properties.Transform(), IntRect(0, 0, 800, 600));
- EXPECT_THAT(
RootPaintController().PaintChunks(),
ElementsAre(
IsPaintChunk(
- 0, 1,
+ 0, 0,
PaintChunk::Id(GetLayoutView(), DisplayItem::kScrollHitTest),
GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
- scroll_hit_test_data),
- IsPaintChunk(1, 2,
+ &scroll_hit_test_data, IntRect(0, 0, 800, 600)),
+ IsPaintChunk(0, 1,
PaintChunk::Id(ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
scrolling_contents_properties)));
} else {
- // Because the frame composited scrolls, no scroll hit test display item is
- // needed.
+ // Because the frame composited scrolls, no scroll hit test data is needed.
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType)));
- EXPECT_THAT(RootPaintController().PaintChunks(),
- ElementsAre(IsPaintChunk(
- 0, 1,
- PaintChunk::Id(ViewScrollingBackgroundClient(),
- kDocumentBackgroundType),
- GetLayoutView().FirstFragment().ContentsProperties())));
+ EXPECT_THAT(
+ RootPaintController().PaintChunks(),
+ ElementsAre(IsPaintChunk(0, 1,
+ PaintChunk::Id(ViewScrollingBackgroundClient(),
+ kDocumentBackgroundType),
+ scrolling_contents_properties)));
}
}
-TEST_P(ViewPainterScrollHitTestTest, FrameScrollHitTestProperties) {
+TEST_P(ViewPainterTest, FrameScrollHitTestProperties) {
// This test depends on the CompositeAfterPaint behavior of painting solid
// color backgrounds into both the non-scrolled and scrolled spaces.
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
@@ -181,16 +171,10 @@ TEST_P(ViewPainterScrollHitTestTest, FrameScrollHitTestProperties) {
<div id='child'></div>
)HTML");
- auto& html =
- To<LayoutBlock>(*GetDocument().documentElement()->GetLayoutObject());
auto& child = *GetLayoutObjectByElementId("child");
- // The scroll hit test should be before the scrolled contents to ensure the
- // hit test does not prevent the background squashing with the scrolling
- // contents.
EXPECT_THAT(RootPaintController().GetDisplayItemList(),
- ElementsAre(IsSameId(&GetLayoutView(), kScrollHitTestType),
- IsSameId(&ViewScrollingBackgroundClient(),
+ ElementsAre(IsSameId(&ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
IsSameId(&child, kBackgroundType)));
@@ -198,24 +182,24 @@ TEST_P(ViewPainterScrollHitTestTest, FrameScrollHitTestProperties) {
const auto& view_contents_properties =
GetLayoutView().FirstFragment().ContentsProperties();
HitTestData scroll_hit_test_data;
- scroll_hit_test_data.SetScrollHitTest(&view_contents_properties.Transform(),
- IntRect(0, 0, 800, 600));
+ scroll_hit_test_data.scroll_translation =
+ &view_contents_properties.Transform();
+ scroll_hit_test_data.scroll_hit_test_rect = IntRect(0, 0, 800, 600);
+ // The scroll hit test should be before the scrolled contents to ensure the
+ // hit test does not prevent the background squashing with the scrolling
+ // contents.
EXPECT_THAT(
paint_chunks,
ElementsAre(
IsPaintChunk(
- 0, 1,
+ 0, 0,
PaintChunk::Id(GetLayoutView(), DisplayItem::kScrollHitTest),
GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
- scroll_hit_test_data),
- IsPaintChunk(1, 2,
+ &scroll_hit_test_data),
+ IsPaintChunk(0, 2,
PaintChunk::Id(ViewScrollingBackgroundClient(),
kDocumentBackgroundType),
- view_contents_properties),
- IsPaintChunk(2, 3,
- PaintChunk::Id(*html.Layer(),
- kNonScrollingContentsBackgroundChunkType),
- html.FirstFragment().ContentsProperties())));
+ view_contents_properties)));
// The scroll hit test should not be scrolled and should not be clipped.
const auto& scroll_hit_test_chunk = RootPaintController().PaintChunks()[0];
@@ -224,25 +208,22 @@ TEST_P(ViewPainterScrollHitTestTest, FrameScrollHitTestProperties) {
EXPECT_EQ(nullptr, scroll_hit_test_transform.ScrollNode());
const auto& scroll_hit_test_clip = scroll_hit_test_chunk.properties.Clip();
EXPECT_EQ(FloatRect(LayoutRect::InfiniteIntRect()),
- scroll_hit_test_clip.ClipRect().Rect());
+ scroll_hit_test_clip.UnsnappedClipRect().Rect());
// The scrolled contents should be scrolled and clipped.
- const auto& contents_chunk = RootPaintController().PaintChunks()[2];
+ const auto& contents_chunk = RootPaintController().PaintChunks()[1];
const auto& contents_transform = contents_chunk.properties.Transform();
const auto* contents_scroll = contents_transform.ScrollNode();
EXPECT_EQ(IntSize(800, 2000), contents_scroll->ContentsSize());
EXPECT_EQ(IntRect(0, 0, 800, 600), contents_scroll->ContainerRect());
const auto& contents_clip = contents_chunk.properties.Clip();
- EXPECT_EQ(FloatRect(0, 0, 800, 600), contents_clip.ClipRect().Rect());
+ EXPECT_EQ(FloatRect(0, 0, 800, 600),
+ contents_clip.UnsnappedClipRect().Rect());
- // The scroll hit test display item maintains a reference to a scroll offset
+ // The scroll hit test paint chunk maintains a reference to a scroll offset
// translation node and the contents should be scrolled by this node.
- const auto& scroll_hit_test_display_item =
- static_cast<const ScrollHitTestDisplayItem&>(
- RootPaintController()
- .GetDisplayItemList()[scroll_hit_test_chunk.begin_index]);
EXPECT_EQ(&contents_transform,
- scroll_hit_test_display_item.scroll_offset_node());
+ scroll_hit_test_chunk.hit_test_data->scroll_translation);
}
class ViewPainterTouchActionRectTest : public ViewPainterTest {
@@ -278,56 +259,42 @@ TEST_P(ViewPainterTouchActionRectTest, TouchActionRectScrollingContents) {
auto scrolling_properties =
GetLayoutView().FirstFragment().ContentsProperties();
HitTestData view_hit_test_data;
- view_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 3000));
-
- auto* html =
- To<LayoutBlock>(GetDocument().documentElement()->GetLayoutObject());
- HitTestData html_hit_test_data;
- html_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 3000));
- html_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 3000));
+ view_hit_test_data.touch_action_rects = {{IntRect(0, 0, 800, 3000)},
+ {IntRect(0, 0, 800, 3000)},
+ {IntRect(0, 0, 800, 3000)}};
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
HitTestData non_scrolling_hit_test_data;
- non_scrolling_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 600));
+ non_scrolling_hit_test_data.touch_action_rects = {
+ {IntRect(0, 0, 800, 600)}};
HitTestData scroll_hit_test_data;
- scroll_hit_test_data.SetScrollHitTest(&scrolling_properties.Transform(),
- IntRect(0, 0, 800, 600));
+ scroll_hit_test_data.scroll_translation = &scrolling_properties.Transform();
+ scroll_hit_test_data.scroll_hit_test_rect = IntRect(0, 0, 800, 600);
EXPECT_THAT(
RootPaintController().PaintChunks(),
ElementsAre(
IsPaintChunk(
- 0, 1,
+ 0, 0,
PaintChunk::Id(*GetLayoutView().Layer(),
- DisplayItem::kLayerChunkBackground),
+ DisplayItem::kLayerChunk),
GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
- non_scrolling_hit_test_data),
+ &non_scrolling_hit_test_data, IntRect(0, 0, 800, 600)),
IsPaintChunk(
- 1, 2,
+ 0, 0,
PaintChunk::Id(GetLayoutView(), DisplayItem::kScrollHitTest),
GetLayoutView().FirstFragment().LocalBorderBoxProperties(),
- scroll_hit_test_data),
+ &scroll_hit_test_data, IntRect(0, 0, 800, 600)),
IsPaintChunk(
- 2, 4, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
- scrolling_properties, view_hit_test_data),
- IsPaintChunk(4, 6,
- PaintChunk::Id(*html->Layer(),
- kNonScrollingBackgroundChunkType),
- scrolling_properties, html_hit_test_data)));
+ 0, 1, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
+ scrolling_properties, &view_hit_test_data,
+ IntRect(0, 0, 800, 3000))));
} else {
EXPECT_THAT(
RootPaintController().PaintChunks(),
- ElementsAre(
- IsPaintChunk(
- 0, 2, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
- scrolling_properties, view_hit_test_data),
- IsPaintChunk(2, 4,
- PaintChunk::Id(*html->Layer(),
- kNonScrollingBackgroundChunkType),
- scrolling_properties, html_hit_test_data)));
+ ElementsAre(IsPaintChunk(
+ 0, 1, PaintChunk::Id(scrolling_client, kDocumentBackgroundType),
+ scrolling_properties, &view_hit_test_data,
+ IntRect(0, 0, 800, 3000))));
}
}
@@ -354,49 +321,46 @@ TEST_P(ViewPainterTouchActionRectTest, TouchActionRectNonScrollingContents) {
auto non_scrolling_properties =
view->FirstFragment().LocalBorderBoxProperties();
HitTestData view_hit_test_data;
- view_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 600));
- auto* html =
- To<LayoutBlock>(GetDocument().documentElement()->GetLayoutObject());
+ view_hit_test_data.touch_action_rects = {{IntRect(0, 0, 800, 600)}};
+ auto* html = GetDocument().documentElement()->GetLayoutBox();
auto scrolling_properties = view->FirstFragment().ContentsProperties();
HitTestData scrolling_hit_test_data;
- scrolling_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 3000));
- scrolling_hit_test_data.touch_action_rects.emplace_back(
- LayoutRect(0, 0, 800, 3000));
+ scrolling_hit_test_data.touch_action_rects = {{IntRect(0, 0, 800, 3000)},
+ {IntRect(0, 0, 800, 3000)}};
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
HitTestData scroll_hit_test_data;
- scroll_hit_test_data.SetScrollHitTest(&scrolling_properties.Transform(),
- IntRect(0, 0, 800, 600));
+ scroll_hit_test_data.scroll_translation = &scrolling_properties.Transform();
+ scroll_hit_test_data.scroll_hit_test_rect = IntRect(0, 0, 800, 600);
EXPECT_THAT(
RootPaintController().PaintChunks(),
ElementsAre(
- IsPaintChunk(0, 2,
- PaintChunk::Id(*view->Layer(),
- DisplayItem::kLayerChunkBackground),
- non_scrolling_properties, view_hit_test_data),
- IsPaintChunk(2, 3,
+ IsPaintChunk(
+ 0, 1, PaintChunk::Id(*view->Layer(), DisplayItem::kLayerChunk),
+ non_scrolling_properties, &view_hit_test_data,
+ IntRect(0, 0, 800, 600)),
+ IsPaintChunk(1, 1,
PaintChunk::Id(*view, DisplayItem::kScrollHitTest),
- non_scrolling_properties, scroll_hit_test_data),
- IsPaintChunk(3, 5,
- PaintChunk::Id(*html->Layer(),
- kNonScrollingBackgroundChunkType),
- scrolling_properties, scrolling_hit_test_data)));
+ non_scrolling_properties, &scroll_hit_test_data,
+ IntRect(0, 0, 800, 600)),
+ IsPaintChunk(
+ 1, 1, PaintChunk::Id(*html->Layer(), DisplayItem::kLayerChunk),
+ scrolling_properties, &scrolling_hit_test_data,
+ IntRect(0, 0, 800, 3000))));
} else {
auto& non_scrolling_paint_controller =
view->Layer()->GraphicsLayerBacking(view)->GetPaintController();
EXPECT_THAT(
non_scrolling_paint_controller.PaintChunks(),
ElementsAre(IsPaintChunk(
- 0, 2,
- PaintChunk::Id(*view->Layer(), kNonScrollingBackgroundChunkType),
- non_scrolling_properties, view_hit_test_data)));
+ 0, 1, PaintChunk::Id(*view->Layer(), DisplayItem::kLayerChunk),
+ non_scrolling_properties, &view_hit_test_data,
+ IntRect(0, 0, 800, 600))));
EXPECT_THAT(
RootPaintController().PaintChunks(),
ElementsAre(IsPaintChunk(
- 0, 2,
- PaintChunk::Id(*html->Layer(), kNonScrollingBackgroundChunkType),
- scrolling_properties, scrolling_hit_test_data)));
+ 0, 0, PaintChunk::Id(*html->Layer(), DisplayItem::kLayerChunk),
+ scrolling_properties, &scrolling_hit_test_data,
+ IntRect(0, 0, 800, 3000))));
}
}