Commit 02a5799e authored by Chris Harrelson's avatar Chris Harrelson Committed by Commit Bot

[ForeignObject] Paint foreign objects during the foreground phase of normal-flow

descendants.

When <foreignObject> was made a stacking context, it also had the side-effect of
painting it at the same time as positioned elements. This is a change to painting
order and caused a regression. Instead, implement a new mechanism by which a
"replaced normal-flow stacking" element paints during the foreground phase
of the LayoutObject paint tree walk.

This is used for now just for <foreignObject>, but may be applied to other
replaced elements such as iframes or embedded objects in the future.

Bug:842668

Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I450944986abfb6610084444abf2724e7406145cf
Reviewed-on: https://chromium-review.googlesource.com/1060333
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: default avatarTien-Ren Chen <trchen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#559401}
parent 39a7832e
<!doctype HTML>
<!doctype HTML>
<style>
* {
margin: 0
}
</style>
<svg style="width: 500px; height: 500px">
<rect x="0" y="0" width="100%" height="100%" style="fill: blue"/>
<rect x="0" y="0" width="50%" height="50%"/>
</svg>
<!doctype HTML>
<link rel="match" href="foreign-object-paints-before-rect-expected.html">
<link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#embedded-ForeignObjectElement"/>
<style>
* {
margin: 0
}
</style>
<!-- Test that the <foreignObject> root element paints in element order
within the SVG, but content within it is atomic. -->
<svg style="width: 500px; height: 500px">
<foreignObject width="100%" height="100%">
<div style="width: 500px; height: 500px; background: blue"></div>
</foreignObject>
<rect x="0" y="0" width="50%" height="50%"/>
</svg>
......@@ -9,12 +9,12 @@
{
"object": "LayoutSVGForeignObject foreignObject",
"rect": [108, 8, 100, 100],
"reason": "paint property change"
"reason": "chunk appeared"
},
{
"object": "LayoutSVGForeignObject foreignObject",
"rect": [8, 8, 100, 100],
"reason": "paint property change"
"reason": "chunk disappeared"
}
]
}
......
......@@ -20,12 +20,12 @@
{
"object": "LayoutSVGForeignObject foreignObject",
"rect": [108, 8, 100, 100],
"reason": "paint property change"
"reason": "chunk appeared"
},
{
"object": "LayoutSVGForeignObject foreignObject",
"rect": [8, 8, 100, 100],
"reason": "paint property change"
"reason": "chunk disappeared"
}
]
}
......
......@@ -100,6 +100,8 @@ class LayoutSVGForeignObject final : public LayoutSVGBlock {
bool needs_transform_update_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSVGForeignObject, IsSVGForeignObject());
} // namespace blink
#endif
......@@ -26,6 +26,13 @@ are treated in different ways during painting:
* Stacking contexts: elements with non-auto z-indices or other properties
that affect stacking e.g. transform, opacity, blend-mode.
* Replaced normal-flow stacking elements: [replaced elements](https://html.spec.whatwg.org/multipage/rendering.html#replaced-elements)
that do not have non-auto z-index but are stacking contexts for
elements below them. Right now the only example is SVG <foreignObject>.
The difference between these elements and regular stacking contexts is
that they paint in the foreground phase of the painting algorithm
(as opposed to the positioned descendants phase).
* Elements that are not real stacking contexts but are treated as stacking
contexts but don't manage other stacked elements. Their z-ordering are
managed by real stacking contexts. They are positioned elements with
......
......@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
#include "third_party/blink/renderer/core/paint/box_decoration_data.h"
......@@ -20,6 +21,7 @@
#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/scroll_recorder.h"
#include "third_party/blink/renderer/core/paint/svg_foreign_object_painter.h"
#include "third_party/blink/renderer/core/paint/theme_painter.h"
#include "third_party/blink/renderer/platform/geometry/layout_point.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
......@@ -42,9 +44,13 @@ void BoxPainter::PaintChildren(const PaintInfo& paint_info,
PaintInfo child_info(paint_info);
for (LayoutObject* child = layout_box_.SlowFirstChild(); child;
child = child->NextSibling()) {
if (!child->IsBoxModelObject() ||
!ToLayoutBoxModelObject(child)->HasSelfPaintingLayer())
if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
child->IsSVGForeignObject()) {
SVGForeignObjectPainter(ToLayoutSVGForeignObject(*child))
.PaintLayer(paint_info);
} else {
child->Paint(child_info, paint_offset);
}
}
}
......
......@@ -1019,6 +1019,17 @@ PaintResult PaintLayerPainter::PaintSingleFragment(
paint_flags, &fragment);
}
// See
// https://chromium.googlesource.com/chromium/src.git/+/master/third_party/blink/renderer/core/paint/README.md
// for the definition of a replaced normal-flow stacking element.
static bool IsReplacedNormalFlowStacking(const PaintLayer& child) {
if (!child.GetLayoutObject().IsSVGForeignObject())
return false;
if (!child.GetLayoutObject().StyleRef().HasAutoZIndex())
return false;
return true;
}
PaintResult PaintLayerPainter::PaintChildren(
unsigned children_to_visit,
GraphicsContext& context,
......@@ -1053,6 +1064,9 @@ PaintResult PaintLayerPainter::PaintChildren(
painting_info.GetGlobalPaintFlags()))
continue;
if (IsReplacedNormalFlowStacking(*child->Layer()))
continue;
PaintLayerPaintingInfo child_painting_info = painting_info;
child_painting_info.scroll_offset_accumulation =
scroll_offset_accumulation_for_children;
......
......@@ -7,11 +7,13 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_container.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_viewport_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/paint/float_clip_recorder.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/svg_foreign_object_painter.h"
#include "third_party/blink/renderer/core/paint/svg_paint_context.h"
#include "third_party/blink/renderer/core/svg/svg_svg_element.h"
......@@ -83,8 +85,11 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
if (continue_rendering) {
for (LayoutObject* child = layout_svg_container_.FirstChild(); child;
child = child->NextSibling()) {
if (!child->IsBoxModelObject() ||
!ToLayoutBoxModelObject(child)->HasSelfPaintingLayer()) {
if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
child->IsSVGForeignObject()) {
SVGForeignObjectPainter(ToLayoutSVGForeignObject(*child))
.PaintLayer(paint_context.GetPaintInfo());
} else {
child->Paint(paint_context.GetPaintInfo(), IntPoint());
}
}
......
......@@ -12,6 +12,7 @@
#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"
#include "third_party/blink/renderer/core/paint/svg_paint_context.h"
namespace blink {
......@@ -34,6 +35,28 @@ class BlockPainterDelegate : public LayoutBlock {
} // namespace
void SVGForeignObjectPainter::PaintLayer(const PaintInfo& paint_info) {
if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
return;
if (paint_info.phase != PaintPhase::kForeground &&
paint_info.phase != PaintPhase::kSelection)
return;
// Early out in the case of trying to paint an image filter before
// pre-paint has finished.
if (!layout_svg_foreign_object_.FirstFragment().HasLocalBorderBoxProperties())
return;
// <foreignObject> is a replaced normal-flow stacking element.
// See IsReplacedNormalFlowStacking in paint_layer_painter.cc.
PaintLayerPaintingInfo layer_painting_info(
layout_svg_foreign_object_.Layer(),
LayoutRect(paint_info.GetCullRect().rect_),
paint_info.GetGlobalPaintFlags(), LayoutSize());
PaintLayerPainter(*layout_svg_foreign_object_.Layer())
.Paint(paint_info.context, layer_painting_info, paint_info.PaintFlags());
}
void SVGForeignObjectPainter::Paint(const PaintInfo& paint_info) {
if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
if (paint_info.phase != PaintPhase::kForeground &&
......
......@@ -21,6 +21,8 @@ class SVGForeignObjectPainter {
: layout_svg_foreign_object_(layout_svg_foreign_object) {}
void Paint(const PaintInfo&);
void PaintLayer(const PaintInfo& paint_info);
private:
const LayoutSVGForeignObject& layout_svg_foreign_object_;
};
......
......@@ -53,6 +53,7 @@ class PLATFORM_EXPORT CullRect {
// TODO(chrishtr): temporary while we implement CullRect everywhere.
friend class FramePainter;
friend class GridPainter;
friend class SVGForeignObjectPainter;
friend class SVGInlineTextBoxPainter;
friend class SVGPaintContext;
friend class SVGRootInlineBoxPainter;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment