Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(575)

Side by Side Diff: third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp

Issue 2404213004: Implement incremental paint property tree rebuilding (Closed)
Patch Set: Cleanup needsUpdate finder construction, tighten reasons for updating a property subtree, misc clea… Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/paint/PaintPropertyTreeBuilder.h" 5 #include "core/paint/PaintPropertyTreeBuilder.h"
6 6
7 #include "core/frame/FrameView.h" 7 #include "core/frame/FrameView.h"
8 #include "core/frame/LocalFrame.h" 8 #include "core/frame/LocalFrame.h"
9 #include "core/frame/Settings.h" 9 #include "core/frame/Settings.h"
10 #include "core/layout/LayoutInline.h" 10 #include "core/layout/LayoutInline.h"
11 #include "core/layout/LayoutPart.h" 11 #include "core/layout/LayoutPart.h"
12 #include "core/layout/LayoutView.h" 12 #include "core/layout/LayoutView.h"
13 #include "core/layout/svg/LayoutSVGRoot.h" 13 #include "core/layout/svg/LayoutSVGRoot.h"
14 #include "core/paint/FindPropertiesNeedingUpdate.h"
14 #include "core/paint/ObjectPaintProperties.h" 15 #include "core/paint/ObjectPaintProperties.h"
15 #include "core/paint/PaintLayer.h" 16 #include "core/paint/PaintLayer.h"
16 #include "core/paint/SVGRootPainter.h" 17 #include "core/paint/SVGRootPainter.h"
17 #include "platform/transforms/TransformationMatrix.h" 18 #include "platform/transforms/TransformationMatrix.h"
18 #include "wtf/PtrUtil.h" 19 #include "wtf/PtrUtil.h"
19 #include <memory> 20 #include <memory>
20 21
21 namespace blink { 22 namespace blink {
22 23
23 namespace { 24 namespace {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 context.current.scroll = context.absolutePosition.scroll = 66 context.current.scroll = context.absolutePosition.scroll =
66 context.fixedPosition.scroll = rootScrollNode(); 67 context.fixedPosition.scroll = rootScrollNode();
67 68
68 // Ensure scroll tree properties are reset. They will be rebuilt during the 69 // Ensure scroll tree properties are reset. They will be rebuilt during the
69 // tree walk. 70 // tree walk.
70 rootScrollNode()->clearMainThreadScrollingReasons(); 71 rootScrollNode()->clearMainThreadScrollingReasons();
71 72
72 return context; 73 return context;
73 } 74 }
74 75
75 const TransformPaintPropertyNode* updateFrameViewPreTranslation( 76 void updateFrameViewPreTranslation(
76 FrameView& frameView, 77 FrameView& frameView,
77 PassRefPtr<const TransformPaintPropertyNode> parent, 78 PassRefPtr<const TransformPaintPropertyNode> parent,
78 const TransformationMatrix& matrix, 79 const TransformationMatrix& matrix,
79 const FloatPoint3D& origin) { 80 const FloatPoint3D& origin) {
80 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 81 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
81 if (TransformPaintPropertyNode* existingPreTranslation = 82 if (auto* existingPreTranslation = frameView.preTranslation()) {
82 frameView.preTranslation())
83 existingPreTranslation->update(std::move(parent), matrix, origin); 83 existingPreTranslation->update(std::move(parent), matrix, origin);
84 else 84 } else {
85 frameView.setPreTranslation( 85 frameView.setPreTranslation(
86 TransformPaintPropertyNode::create(std::move(parent), matrix, origin)); 86 TransformPaintPropertyNode::create(std::move(parent), matrix, origin));
87 return frameView.preTranslation(); 87 }
88 } 88 }
89 89
90 const ClipPaintPropertyNode* updateFrameViewContentClip( 90 void updateFrameViewContentClip(
91 FrameView& frameView, 91 FrameView& frameView,
92 PassRefPtr<const ClipPaintPropertyNode> parent, 92 PassRefPtr<const ClipPaintPropertyNode> parent,
93 PassRefPtr<const TransformPaintPropertyNode> localTransformSpace, 93 PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
94 const FloatRoundedRect& clipRect) { 94 const FloatRoundedRect& clipRect) {
95 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 95 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
96 if (ClipPaintPropertyNode* existingContentClip = frameView.contentClip()) 96 if (auto* existingContentClip = frameView.contentClip()) {
97 existingContentClip->update(std::move(parent), 97 existingContentClip->update(std::move(parent),
98 std::move(localTransformSpace), clipRect); 98 std::move(localTransformSpace), clipRect);
99 else 99 } else {
100 frameView.setContentClip(ClipPaintPropertyNode::create( 100 frameView.setContentClip(ClipPaintPropertyNode::create(
101 std::move(parent), std::move(localTransformSpace), clipRect)); 101 std::move(parent), std::move(localTransformSpace), clipRect));
102 return frameView.contentClip(); 102 }
103 } 103 }
104 104
105 const TransformPaintPropertyNode* updateFrameViewScrollTranslation( 105 void updateFrameViewScrollTranslation(
106 FrameView& frameView, 106 FrameView& frameView,
107 PassRefPtr<const TransformPaintPropertyNode> parent, 107 PassRefPtr<const TransformPaintPropertyNode> parent,
108 const TransformationMatrix& matrix, 108 const TransformationMatrix& matrix,
109 const FloatPoint3D& origin) { 109 const FloatPoint3D& origin) {
110 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 110 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
111 if (TransformPaintPropertyNode* existingScrollTranslation = 111 if (auto* existingScrollTranslation = frameView.scrollTranslation()) {
112 frameView.scrollTranslation())
113 existingScrollTranslation->update(std::move(parent), matrix, origin); 112 existingScrollTranslation->update(std::move(parent), matrix, origin);
114 else 113 } else {
115 frameView.setScrollTranslation( 114 frameView.setScrollTranslation(
116 TransformPaintPropertyNode::create(std::move(parent), matrix, origin)); 115 TransformPaintPropertyNode::create(std::move(parent), matrix, origin));
117 return frameView.scrollTranslation(); 116 }
118 } 117 }
119 118
120 ScrollPaintPropertyNode* updateFrameViewScroll( 119 void updateFrameViewScroll(
121 FrameView& frameView, 120 FrameView& frameView,
122 PassRefPtr<ScrollPaintPropertyNode> parent, 121 PassRefPtr<ScrollPaintPropertyNode> parent,
123 PassRefPtr<const TransformPaintPropertyNode> scrollOffset, 122 PassRefPtr<const TransformPaintPropertyNode> scrollOffset,
124 const IntSize& clip, 123 const IntSize& clip,
125 const IntSize& bounds, 124 const IntSize& bounds,
126 bool userScrollableHorizontal, 125 bool userScrollableHorizontal,
127 bool userScrollableVertical) { 126 bool userScrollableVertical) {
128 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 127 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
129 if (ScrollPaintPropertyNode* existingScroll = frameView.scroll()) 128 if (auto* existingScroll = frameView.scroll()) {
130 existingScroll->update(std::move(parent), std::move(scrollOffset), clip, 129 existingScroll->update(std::move(parent), std::move(scrollOffset), clip,
131 bounds, userScrollableHorizontal, 130 bounds, userScrollableHorizontal,
132 userScrollableVertical); 131 userScrollableVertical);
133 else 132 } else {
134 frameView.setScroll(ScrollPaintPropertyNode::create( 133 frameView.setScroll(ScrollPaintPropertyNode::create(
135 std::move(parent), std::move(scrollOffset), clip, bounds, 134 std::move(parent), std::move(scrollOffset), clip, bounds,
136 userScrollableHorizontal, userScrollableVertical)); 135 userScrollableHorizontal, userScrollableVertical));
137 return frameView.scroll(); 136 }
138 } 137 }
139 138
140 void PaintPropertyTreeBuilder::buildTreeNodes( 139 void PaintPropertyTreeBuilder::updateProperties(
141 FrameView& frameView, 140 FrameView& frameView,
142 PaintPropertyTreeBuilderContext& context) { 141 PaintPropertyTreeBuilderContext& context) {
143 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { 142 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
144 LayoutView* layoutView = frameView.layoutView(); 143 LayoutView* layoutView = frameView.layoutView();
145 if (!layoutView) 144 if (!layoutView)
146 return; 145 return;
147 146
148 TransformationMatrix frameTranslate; 147 #if DCHECK_IS_ON()
149 frameTranslate.translate(frameView.x() + layoutView->location().x() + 148 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(*layoutView);
150 context.current.paintOffset.x(), 149 #endif
151 frameView.y() + layoutView->location().y() + 150
152 context.current.paintOffset.y()); 151 if (layoutView->needsPaintPropertyUpdate()) {
153 context.current.transform = 152 TransformationMatrix frameTranslate;
154 layoutView->getMutableForPainting() 153 frameTranslate.translate(frameView.x() + layoutView->location().x() +
155 .ensurePaintProperties() 154 context.current.paintOffset.x(),
156 .updatePaintOffsetTranslation(context.current.transform, 155 frameView.y() + layoutView->location().y() +
157 frameTranslate, FloatPoint3D()); 156 context.current.paintOffset.y());
157 layoutView->getMutableForPainting()
158 .ensurePaintProperties()
159 .updatePaintOffsetTranslation(context.current.transform,
160 frameTranslate, FloatPoint3D());
161 }
162
163 const auto* properties = layoutView->paintProperties();
164 DCHECK(properties && properties->paintOffsetTranslation());
165 context.current.transform = properties->paintOffsetTranslation();
158 context.current.paintOffset = LayoutPoint(); 166 context.current.paintOffset = LayoutPoint();
159 context.current.renderingContextID = 0; 167 context.current.renderingContextID = 0;
160 context.current.shouldFlattenInheritedTransform = true; 168 context.current.shouldFlattenInheritedTransform = true;
161 context.absolutePosition = context.current; 169 context.absolutePosition = context.current;
162 context.containerForAbsolutePosition = 170 context.containerForAbsolutePosition =
163 nullptr; // This will get set in updateOutOfFlowContext(). 171 nullptr; // This will get set in updateOutOfFlowContext().
164 context.fixedPosition = context.current; 172 context.fixedPosition = context.current;
165 return; 173 return;
166 } 174 }
167 175
168 TransformationMatrix frameTranslate; 176 #if DCHECK_IS_ON()
169 frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), 177 FindFrameViewPropertiesNeedingUpdateScope checkNeedsUpdateScope(&frameView);
170 frameView.y() + context.current.paintOffset.y()); 178 #endif
171 context.current.transform = updateFrameViewPreTranslation(
172 frameView, context.current.transform, frameTranslate, FloatPoint3D());
173 179
174 FloatRoundedRect contentClip( 180 if (frameView.needsPaintPropertyUpdate()) {
175 IntRect(IntPoint(), frameView.visibleContentSize())); 181 TransformationMatrix frameTranslate;
176 context.current.clip = updateFrameViewContentClip( 182 frameTranslate.translate(frameView.x() + context.current.paintOffset.x(),
177 frameView, context.current.clip, frameView.preTranslation(), contentClip); 183 frameView.y() + context.current.paintOffset.y());
184 updateFrameViewPreTranslation(frameView, context.current.transform,
185 frameTranslate, FloatPoint3D());
178 186
179 // Record the fixed properties before any scrolling occurs. 187 FloatRoundedRect contentClip(
180 const auto* fixedTransformNode = context.current.transform; 188 IntRect(IntPoint(), frameView.visibleContentSize()));
181 auto* fixedScrollNode = context.current.scroll; 189 updateFrameViewContentClip(frameView, context.current.clip,
190 frameView.preTranslation(), contentClip);
182 191
183 ScrollOffset scrollOffset = frameView.scrollOffset(); 192 ScrollOffset scrollOffset = frameView.scrollOffset();
184 if (frameView.isScrollable() || !scrollOffset.isZero()) { 193 if (frameView.isScrollable() || !scrollOffset.isZero()) {
185 TransformationMatrix frameScroll; 194 TransformationMatrix frameScroll;
186 frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); 195 frameScroll.translate(-scrollOffset.width(), -scrollOffset.height());
187 context.current.transform = updateFrameViewScrollTranslation( 196 updateFrameViewScrollTranslation(frameView, frameView.preTranslation(),
188 frameView, frameView.preTranslation(), frameScroll, FloatPoint3D()); 197 frameScroll, FloatPoint3D());
189 198
190 IntSize scrollClip = frameView.visibleContentSize(); 199 IntSize scrollClip = frameView.visibleContentSize();
191 IntSize scrollBounds = frameView.contentsSize(); 200 IntSize scrollBounds = frameView.contentsSize();
192 bool userScrollableHorizontal = 201 bool userScrollableHorizontal =
193 frameView.userInputScrollable(HorizontalScrollbar); 202 frameView.userInputScrollable(HorizontalScrollbar);
194 bool userScrollableVertical = 203 bool userScrollableVertical =
195 frameView.userInputScrollable(VerticalScrollbar); 204 frameView.userInputScrollable(VerticalScrollbar);
196 context.current.scroll = updateFrameViewScroll( 205 updateFrameViewScroll(frameView, context.current.scroll,
197 frameView, context.current.scroll, frameView.scrollTranslation(), 206 frameView.scrollTranslation(), scrollClip,
198 scrollClip, scrollBounds, userScrollableHorizontal, 207 scrollBounds, userScrollableHorizontal,
199 userScrollableVertical); 208 userScrollableVertical);
200 } else { 209 } else {
201 // Ensure pre-existing properties are cleared when there is no scrolling. 210 // Ensure pre-existing properties are cleared when there is no scrolling.
202 frameView.setScrollTranslation(nullptr); 211 frameView.setScrollTranslation(nullptr);
203 frameView.setScroll(nullptr); 212 frameView.setScroll(nullptr);
213 }
204 } 214 }
205 215
206 // Initialize the context for current, absolute and fixed position cases. 216 // Initialize the context for current, absolute and fixed position cases.
207 // They are the same, except that scroll translation does not apply to 217 // They are the same, except that scroll translation does not apply to
208 // fixed position descendants. 218 // fixed position descendants.
219 const auto* fixedTransformNode = frameView.preTranslation()
220 ? frameView.preTranslation()
221 : context.current.transform;
222 auto* fixedScrollNode = context.current.scroll;
223 DCHECK(frameView.preTranslation());
224 context.current.transform = frameView.preTranslation();
225 DCHECK(frameView.contentClip());
226 context.current.clip = frameView.contentClip();
227 if (const auto* scrollTranslation = frameView.scrollTranslation())
228 context.current.transform = scrollTranslation;
229 if (auto* scroll = frameView.scroll())
230 context.current.scroll = scroll;
209 context.current.paintOffset = LayoutPoint(); 231 context.current.paintOffset = LayoutPoint();
210 context.current.renderingContextID = 0; 232 context.current.renderingContextID = 0;
211 context.current.shouldFlattenInheritedTransform = true; 233 context.current.shouldFlattenInheritedTransform = true;
212 context.absolutePosition = context.current; 234 context.absolutePosition = context.current;
213 context.containerForAbsolutePosition = nullptr; 235 context.containerForAbsolutePosition = nullptr;
214 context.fixedPosition = context.current; 236 context.fixedPosition = context.current;
215 context.fixedPosition.transform = fixedTransformNode; 237 context.fixedPosition.transform = fixedTransformNode;
216 context.fixedPosition.scroll = fixedScrollNode; 238 context.fixedPosition.scroll = fixedScrollNode;
217 239
218 std::unique_ptr<PropertyTreeState> contentsState( 240 std::unique_ptr<PropertyTreeState> contentsState(
219 new PropertyTreeState(context.current.transform, context.current.clip, 241 new PropertyTreeState(context.current.transform, context.current.clip,
220 context.currentEffect, context.current.scroll)); 242 context.currentEffect, context.current.scroll));
221 frameView.setTotalPropertyTreeStateForContents(std::move(contentsState)); 243 frameView.setTotalPropertyTreeStateForContents(std::move(contentsState));
222 } 244 }
223 245
224 void PaintPropertyTreeBuilder::updatePaintOffsetTranslation( 246 void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
225 const LayoutObject& object, 247 const LayoutObject& object,
226 PaintPropertyTreeBuilderContext& context) { 248 PaintPropertyTreeBuilderContext& context) {
227 // LayoutView's paint offset is updated in the FrameView property update. 249 // LayoutView's paint offset is updated in the FrameView property update.
228 if (object.isLayoutView()) { 250 if (object.isLayoutView()) {
229 DCHECK(context.current.paintOffset == LayoutPoint()); 251 DCHECK(context.current.paintOffset == LayoutPoint());
230 return; 252 return;
231 } 253 }
232 254
255 bool usesPaintOffsetTranslation = false;
233 if (object.isBoxModelObject() && 256 if (object.isBoxModelObject() &&
234 context.current.paintOffset != LayoutPoint()) { 257 context.current.paintOffset != LayoutPoint()) {
235 // TODO(trchen): Eliminate PaintLayer dependency. 258 // TODO(trchen): Eliminate PaintLayer dependency.
236 PaintLayer* layer = toLayoutBoxModelObject(object).layer(); 259 PaintLayer* layer = toLayoutBoxModelObject(object).layer();
237 if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase)) { 260 if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase))
238 // We should use the same subpixel paint offset values for snapping 261 usesPaintOffsetTranslation = true;
239 // regardless of whether a transform is present. If there is a transform 262 }
240 // we round the paint offset but keep around the residual fractional
241 // component for the transformed content to paint with. In spv1 this was
242 // called "subpixel accumulation". For more information, see
243 // PaintLayer::subpixelAccumulation() and
244 // PaintLayerPainter::paintFragmentByApplyingTransform.
245 IntPoint roundedPaintOffset =
246 roundedIntPoint(context.current.paintOffset);
247 LayoutPoint fractionalPaintOffset =
248 LayoutPoint(context.current.paintOffset - roundedPaintOffset);
249 263
250 context.current.transform = 264 // We should use the same subpixel paint offset values for snapping
251 object.getMutableForPainting() 265 // regardless of whether a transform is present. If there is a transform
252 .ensurePaintProperties() 266 // we round the paint offset but keep around the residual fractional
253 .updatePaintOffsetTranslation( 267 // component for the transformed content to paint with. In spv1 this was
254 context.current.transform, 268 // called "subpixel accumulation". For more information, see
255 TransformationMatrix().translate(roundedPaintOffset.x(), 269 // PaintLayer::subpixelAccumulation() and
256 roundedPaintOffset.y()), 270 // PaintLayerPainter::paintFragmentByApplyingTransform.
257 FloatPoint3D(), 271 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
258 context.current.shouldFlattenInheritedTransform, 272 LayoutPoint fractionalPaintOffset =
259 context.current.renderingContextID); 273 LayoutPoint(context.current.paintOffset - roundedPaintOffset);
260 context.current.paintOffset = fractionalPaintOffset; 274
261 return; 275 if (object.needsPaintPropertyUpdate()) {
276 if (usesPaintOffsetTranslation) {
277 object.getMutableForPainting()
278 .ensurePaintProperties()
279 .updatePaintOffsetTranslation(
280 context.current.transform,
281 TransformationMatrix().translate(roundedPaintOffset.x(),
282 roundedPaintOffset.y()),
283 FloatPoint3D(), context.current.shouldFlattenInheritedTransform,
284 context.current.renderingContextID);
285 } else {
286 if (auto* properties = object.getMutableForPainting().paintProperties())
287 properties->clearPaintOffsetTranslation();
262 } 288 }
263 } 289 }
264 290
265 if (auto* properties = object.getMutableForPainting().paintProperties()) 291 const auto* properties = object.paintProperties();
266 properties->clearPaintOffsetTranslation(); 292 if (properties && properties->paintOffsetTranslation()) {
293 context.current.transform = properties->paintOffsetTranslation();
294 context.current.paintOffset = fractionalPaintOffset;
295 }
267 } 296 }
268 297
269 static FloatPoint3D transformOrigin(const LayoutBox& box) { 298 static FloatPoint3D transformOrigin(const LayoutBox& box) {
270 const ComputedStyle& style = box.styleRef(); 299 const ComputedStyle& style = box.styleRef();
271 FloatSize borderBoxSize(box.size()); 300 FloatSize borderBoxSize(box.size());
272 return FloatPoint3D( 301 return FloatPoint3D(
273 floatValueForLength(style.transformOriginX(), borderBoxSize.width()), 302 floatValueForLength(style.transformOriginX(), borderBoxSize.width()),
274 floatValueForLength(style.transformOriginY(), borderBoxSize.height()), 303 floatValueForLength(style.transformOriginY(), borderBoxSize.height()),
275 style.transformOriginZ()); 304 style.transformOriginZ());
276 } 305 }
277 306
278 // SVG does not use the general transform update of |updateTransform|, instead 307 // SVG does not use the general transform update of |updateTransform|, instead
279 // creating a transform node for SVG-specific transforms without 3D. 308 // creating a transform node for SVG-specific transforms without 3D.
280 void PaintPropertyTreeBuilder::updateTransformForNonRootSVG( 309 void PaintPropertyTreeBuilder::updateTransformForNonRootSVG(
281 const LayoutObject& object, 310 const LayoutObject& object,
282 PaintPropertyTreeBuilderContext& context) { 311 PaintPropertyTreeBuilderContext& context) {
283 DCHECK(object.isSVG() && !object.isSVGRoot()); 312 DCHECK(object.isSVG() && !object.isSVGRoot());
284 // SVG (other than SVGForeignObject) does not use paint offset internally. 313 // SVG (other than SVGForeignObject) does not use paint offset internally.
285 DCHECK(object.isSVGForeignObject() || 314 DCHECK(object.isSVGForeignObject() ||
286 context.current.paintOffset == LayoutPoint()); 315 context.current.paintOffset == LayoutPoint());
287 316
288 // FIXME(pdr): Refactor this so all non-root SVG objects use the same 317 if (object.needsPaintPropertyUpdate()) {
289 // transform function. 318 // TODO(pdr): Refactor this so all non-root SVG objects use the same
290 const AffineTransform& transform = object.isSVGForeignObject() 319 // transform function.
291 ? object.localSVGTransform() 320 const AffineTransform& transform = object.isSVGForeignObject()
292 : object.localToSVGParentTransform(); 321 ? object.localSVGTransform()
322 : object.localToSVGParentTransform();
323 // TODO(pdr): Check for the presence of a transform instead of the value.
324 // Checking for an identity matrix will cause the property tree structure
325 // to change during animations if the animation passes through the
326 // identity matrix.
327 if (!transform.isIdentity()) {
328 // The origin is included in the local transform, so leave origin empty.
329 object.getMutableForPainting().ensurePaintProperties().updateTransform(
330 context.current.transform, TransformationMatrix(transform),
331 FloatPoint3D());
332 } else {
333 if (auto* properties = object.getMutableForPainting().paintProperties())
334 properties->clearTransform();
335 }
336 }
293 337
294 // FIXME(pdr): Check for the presence of a transform instead of the value. 338 if (object.paintProperties() && object.paintProperties()->transform()) {
295 // Checking for an identity matrix will cause the property tree structure to 339 context.current.transform = object.paintProperties()->transform();
296 // change during animations if the animation passes through the identity 340 context.current.shouldFlattenInheritedTransform = false;
297 // matrix.
298 if (!transform.isIdentity()) {
299 // The origin is included in the local transform, so leave origin empty.
300 context.current.transform =
301 object.getMutableForPainting().ensurePaintProperties().updateTransform(
302 context.current.transform, TransformationMatrix(transform),
303 FloatPoint3D());
304 context.current.renderingContextID = 0; 341 context.current.renderingContextID = 0;
305 context.current.shouldFlattenInheritedTransform = false;
306 } else {
307 if (auto* properties = object.getMutableForPainting().paintProperties())
308 properties->clearTransform();
309 } 342 }
310 } 343 }
311 344
312 void PaintPropertyTreeBuilder::updateTransform( 345 void PaintPropertyTreeBuilder::updateTransform(
313 const LayoutObject& object, 346 const LayoutObject& object,
314 PaintPropertyTreeBuilderContext& context) { 347 PaintPropertyTreeBuilderContext& context) {
315 if (object.isSVG() && !object.isSVGRoot()) { 348 if (object.isSVG() && !object.isSVGRoot()) {
316 updateTransformForNonRootSVG(object, context); 349 updateTransformForNonRootSVG(object, context);
317 return; 350 return;
318 } 351 }
319 352
320 const ComputedStyle& style = object.styleRef(); 353 if (object.needsPaintPropertyUpdate()) {
321 if (object.isBox() && (style.hasTransform() || style.preserves3D())) { 354 const ComputedStyle& style = object.styleRef();
322 TransformationMatrix matrix; 355 if (object.isBox() && (style.hasTransform() || style.preserves3D())) {
323 style.applyTransform(matrix, toLayoutBox(object).size(), 356 TransformationMatrix matrix;
324 ComputedStyle::ExcludeTransformOrigin, 357 style.applyTransform(
325 ComputedStyle::IncludeMotionPath, 358 matrix, toLayoutBox(object).size(),
326 ComputedStyle::IncludeIndependentTransformProperties); 359 ComputedStyle::ExcludeTransformOrigin,
327 FloatPoint3D origin = transformOrigin(toLayoutBox(object)); 360 ComputedStyle::IncludeMotionPath,
361 ComputedStyle::IncludeIndependentTransformProperties);
328 362
329 unsigned renderingContextID = context.current.renderingContextID; 363 // TODO(trchen): transform-style should only be respected if a PaintLayer
330 unsigned renderingContextIDForChildren = 0; 364 // is created.
331 bool flattensInheritedTransform =
332 context.current.shouldFlattenInheritedTransform;
333 bool childrenFlattenInheritedTransform = true;
334
335 // TODO(trchen): transform-style should only be respected if a PaintLayer
336 // is created.
337 if (style.preserves3D()) {
338 // If a node with transform-style: preserve-3d does not exist in an 365 // If a node with transform-style: preserve-3d does not exist in an
339 // existing rendering context, it establishes a new one. 366 // existing rendering context, it establishes a new one.
340 if (!renderingContextID) 367 unsigned renderingContextID = context.current.renderingContextID;
368 if (style.preserves3D() && !renderingContextID)
341 renderingContextID = PtrHash<const LayoutObject>::hash(&object); 369 renderingContextID = PtrHash<const LayoutObject>::hash(&object);
342 renderingContextIDForChildren = renderingContextID; 370
343 childrenFlattenInheritedTransform = false; 371 object.getMutableForPainting().ensurePaintProperties().updateTransform(
372 context.current.transform, matrix,
373 transformOrigin(toLayoutBox(object)),
374 context.current.shouldFlattenInheritedTransform, renderingContextID);
375 } else {
376 if (auto* properties = object.getMutableForPainting().paintProperties())
377 properties->clearTransform();
344 } 378 }
379 }
345 380
346 context.current.transform = 381 const auto* properties = object.paintProperties();
347 object.getMutableForPainting().ensurePaintProperties().updateTransform( 382 if (properties && properties->transform()) {
348 context.current.transform, matrix, origin, 383 context.current.transform = properties->transform();
349 flattensInheritedTransform, renderingContextID); 384 unsigned renderingContextID = properties->transform()->renderingContextID();
350 context.current.renderingContextID = renderingContextIDForChildren; 385 if (context.current.renderingContextID != renderingContextID) {
351 context.current.shouldFlattenInheritedTransform = 386 context.current.renderingContextID = renderingContextID;
352 childrenFlattenInheritedTransform; 387 context.current.shouldFlattenInheritedTransform = false;
353 } else { 388 } else {
354 if (auto* properties = object.getMutableForPainting().paintProperties()) 389 context.current.renderingContextID = 0;
355 properties->clearTransform(); 390 context.current.shouldFlattenInheritedTransform = true;
391 }
356 } 392 }
357 } 393 }
358 394
359 void PaintPropertyTreeBuilder::updateEffect( 395 void PaintPropertyTreeBuilder::updateEffect(
360 const LayoutObject& object, 396 const LayoutObject& object,
361 PaintPropertyTreeBuilderContext& context) { 397 PaintPropertyTreeBuilderContext& context) {
362 const ComputedStyle& style = object.styleRef(); 398 const ComputedStyle& style = object.styleRef();
363 399
364 if (!style.isStackingContext()) { 400 if (!style.isStackingContext()) {
365 if (ObjectPaintProperties* properties = 401 if (object.needsPaintPropertyUpdate()) {
366 object.getMutableForPainting().paintProperties()) 402 if (auto* properties = object.getMutableForPainting().paintProperties())
367 properties->clearEffect(); 403 properties->clearEffect();
404 }
368 return; 405 return;
369 } 406 }
370 407
371 // TODO(trchen): Can't omit effect node if we have 3D children. 408 if (object.needsPaintPropertyUpdate()) {
372 // TODO(trchen): Can't omit effect node if we have blending children. 409 // TODO(trchen): Can't omit effect node if we have 3D children.
373 bool effectNodeNeeded = false; 410 // TODO(trchen): Can't omit effect node if we have blending children.
411 bool effectNodeNeeded = false;
374 412
375 float opacity = style.opacity(); 413 float opacity = style.opacity();
376 if (opacity != 1.0f) 414 if (opacity != 1.0f)
377 effectNodeNeeded = true; 415 effectNodeNeeded = true;
378 416
379 CompositorFilterOperations filter; 417 CompositorFilterOperations filter;
380 if (object.isSVG() && !object.isSVGRoot()) { 418 if (object.isSVG() && !object.isSVGRoot()) {
381 // TODO(trchen): SVG caches filters in SVGResources. Implement it. 419 // TODO(trchen): SVG caches filters in SVGResources. Implement it.
382 } else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) { 420 } else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) {
383 // TODO(trchen): Eliminate PaintLayer dependency. 421 // TODO(trchen): Eliminate PaintLayer dependency.
384 filter = layer->createCompositorFilterOperationsForFilter(style); 422 filter = layer->createCompositorFilterOperationsForFilter(style);
423 }
424
425 const ClipPaintPropertyNode* outputClip = rootClipNode();
426 // The CSS filter spec didn't specify how filters interact with overflow
427 // clips. The implementation here mimics the old Blink/WebKit behavior for
428 // backward compatibility.
429 // Basically the output of the filter will be affected by clips that applies
430 // to the current element. The descendants that paints into the input of the
431 // filter ignores any clips collected so far. For example:
432 // <div style="overflow:scroll">
433 // <div style="filter:blur(1px);">
434 // <div>A</div>
435 // <div style="position:absolute;">B</div>
436 // </div>
437 // </div>
438 // In this example "A" should be clipped if the filter was not present.
439 // With the filter, "A" will be rastered without clipping, but instead
440 // the blurred result will be clipped.
441 // On the other hand, "B" should not be clipped because the overflow clip is
442 // not in its containing block chain, but as the filter output will be
443 // clipped, so a blurred "B" may still be invisible.
444 if (!filter.isEmpty()) {
445 effectNodeNeeded = true;
446 outputClip = context.current.clip;
447
448 // TODO(trchen): A filter may contain spatial operations such that an
449 // output pixel may depend on an input pixel outside of the output clip.
450 // We should generate a special clip node to represent this expansion.
451 }
452
453 if (effectNodeNeeded) {
454 object.getMutableForPainting().ensurePaintProperties().updateEffect(
455 context.currentEffect, context.current.transform, outputClip,
456 std::move(filter), opacity);
457 } else {
458 if (auto* properties = object.getMutableForPainting().paintProperties())
459 properties->clearEffect();
460 }
385 } 461 }
386 462
387 const ClipPaintPropertyNode* outputClip = rootClipNode(); 463 const auto* properties = object.paintProperties();
388 // The CSS filter spec didn't specify how filters interact with overflow 464 if (properties && properties->effect()) {
389 // clips. The implementation here mimics the old Blink/WebKit behavior for 465 context.currentEffect = properties->effect();
390 // backward compatibility. 466 // TODO(pdr): Once the expansion clip node is created above, it should be
391 // Basically the output of the filter will be affected by clips that applies 467 // used here to update all current clip nodes;
392 // to the current element. The descendants that paints into the input of the
393 // filter ignores any clips collected so far. For example:
394 // <div style="overflow:scroll">
395 // <div style="filter:blur(1px);">
396 // <div>A</div>
397 // <div style="position:absolute;">B</div>
398 // </div>
399 // </div>
400 // In this example "A" should be clipped if the filter was not present.
401 // With the filter, "A" will be rastered without clipping, but instead
402 // the blurred result will be clipped.
403 // On the other hand, "B" should not be clipped because the overflow clip is
404 // not in its containing block chain, but as the filter output will be
405 // clipped, so a blurred "B" may still be invisible.
406 if (!filter.isEmpty()) {
407 effectNodeNeeded = true;
408 outputClip = context.current.clip;
409
410 // TODO(trchen): A filter may contain spatial operations such that an output
411 // pixel may depend on an input pixel outside of the output clip. Need to
412 // generate special clip node to hint how to expand clip / cull rect.
413 const ClipPaintPropertyNode* expansionHint = context.current.clip; 468 const ClipPaintPropertyNode* expansionHint = context.current.clip;
414 context.current.clip = context.absolutePosition.clip = 469 context.current.clip = context.absolutePosition.clip =
415 context.fixedPosition.clip = expansionHint; 470 context.fixedPosition.clip = expansionHint;
416 } 471 }
417
418 if (!effectNodeNeeded) {
419 if (ObjectPaintProperties* properties =
420 object.getMutableForPainting().paintProperties())
421 properties->clearEffect();
422 return;
423 }
424
425 context.currentEffect =
426 object.getMutableForPainting().ensurePaintProperties().updateEffect(
427 context.currentEffect, context.current.transform, outputClip,
428 std::move(filter), opacity);
429 } 472 }
430 473
431 void PaintPropertyTreeBuilder::updateCssClip( 474 void PaintPropertyTreeBuilder::updateCssClip(
432 const LayoutObject& object, 475 const LayoutObject& object,
433 PaintPropertyTreeBuilderContext& context) { 476 PaintPropertyTreeBuilderContext& context) {
434 if (object.hasClip()) { 477 if (object.needsPaintPropertyUpdate()) {
435 // Create clip node for descendants that are not fixed position. 478 if (object.hasClip()) {
436 // We don't have to setup context.absolutePosition.clip here because this 479 // Create clip node for descendants that are not fixed position.
437 // object must be a container for absolute position descendants, and will 480 // We don't have to setup context.absolutePosition.clip here because this
438 // copy from in-flow context later at updateOutOfFlowContext() step. 481 // object must be a container for absolute position descendants, and will
439 DCHECK(object.canContainAbsolutePositionObjects()); 482 // copy from in-flow context later at updateOutOfFlowContext() step.
440 LayoutRect clipRect = 483 DCHECK(object.canContainAbsolutePositionObjects());
441 toLayoutBox(object).clipRect(context.current.paintOffset); 484 LayoutRect clipRect =
442 context.current.clip = 485 toLayoutBox(object).clipRect(context.current.paintOffset);
443 object.getMutableForPainting().ensurePaintProperties().updateCssClip( 486 object.getMutableForPainting().ensurePaintProperties().updateCssClip(
444 context.current.clip, context.current.transform, 487 context.current.clip, context.current.transform,
445 FloatRoundedRect(FloatRect(clipRect))); 488 FloatRoundedRect(FloatRect(clipRect)));
446 return; 489 } else {
490 if (auto* properties = object.getMutableForPainting().paintProperties())
491 properties->clearCssClip();
492 }
447 } 493 }
448 494
449 if (auto* properties = object.getMutableForPainting().paintProperties()) 495 const auto* properties = object.paintProperties();
450 properties->clearCssClip(); 496 if (properties && properties->cssClip())
497 context.current.clip = properties->cssClip();
451 } 498 }
452 499
453 void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( 500 void PaintPropertyTreeBuilder::updateLocalBorderBoxContext(
454 const LayoutObject& object, 501 const LayoutObject& object,
455 PaintPropertyTreeBuilderContext& context) { 502 PaintPropertyTreeBuilderContext& context) {
456 // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since 503 if (object.needsPaintPropertyUpdate()) {
457 // we don't need them at the moment. 504 // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since
458 if (!object.isBox() && !object.hasLayer()) 505 // we don't need them at the moment.
459 return; 506 if (!object.isBox() && !object.hasLayer()) {
460 507 if (auto* properties = object.getMutableForPainting().paintProperties())
461 std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset> 508 properties->clearLocalBorderBoxProperties();
462 borderBoxContext = 509 } else {
463 wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset( 510 std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset>
464 context.current.paintOffset, 511 borderBoxContext =
465 PropertyTreeState(context.current.transform, context.current.clip, 512 wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset(
466 context.currentEffect, 513 context.current.paintOffset,
467 context.current.scroll))); 514 PropertyTreeState(context.current.transform,
468 object.getMutableForPainting() 515 context.current.clip, context.currentEffect,
469 .ensurePaintProperties() 516 context.current.scroll)));
470 .setLocalBorderBoxProperties(std::move(borderBoxContext)); 517 object.getMutableForPainting()
518 .ensurePaintProperties()
519 .setLocalBorderBoxProperties(std::move(borderBoxContext));
520 }
521 }
471 } 522 }
472 523
473 // TODO(trchen): Remove this once we bake the paint offset into frameRect. 524 // TODO(trchen): Remove this once we bake the paint offset into frameRect.
474 void PaintPropertyTreeBuilder::updateScrollbarPaintOffset( 525 void PaintPropertyTreeBuilder::updateScrollbarPaintOffset(
475 const LayoutObject& object, 526 const LayoutObject& object,
476 const PaintPropertyTreeBuilderContext& context) { 527 const PaintPropertyTreeBuilderContext& context) {
528 if (!object.needsPaintPropertyUpdate())
529 return;
530
477 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset); 531 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
478 if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) { 532 if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) {
479 if (PaintLayerScrollableArea* scrollableArea = 533 if (PaintLayerScrollableArea* scrollableArea =
480 toLayoutBoxModelObject(object).getScrollableArea()) { 534 toLayoutBoxModelObject(object).getScrollableArea()) {
481 if (scrollableArea->horizontalScrollbar() || 535 if (scrollableArea->horizontalScrollbar() ||
482 scrollableArea->verticalScrollbar()) { 536 scrollableArea->verticalScrollbar()) {
483 auto paintOffset = TransformationMatrix().translate( 537 auto paintOffset = TransformationMatrix().translate(
484 roundedPaintOffset.x(), roundedPaintOffset.y()); 538 roundedPaintOffset.x(), roundedPaintOffset.y());
485 object.getMutableForPainting() 539 object.getMutableForPainting()
486 .ensurePaintProperties() 540 .ensurePaintProperties()
487 .updateScrollbarPaintOffset(context.current.transform, paintOffset, 541 .updateScrollbarPaintOffset(context.current.transform, paintOffset,
488 FloatPoint3D()); 542 FloatPoint3D());
489 return; 543 return;
490 } 544 }
491 } 545 }
492 } 546 }
493 547
494 if (auto* properties = object.getMutableForPainting().paintProperties()) 548 if (auto* properties = object.getMutableForPainting().paintProperties())
495 properties->clearScrollbarPaintOffset(); 549 properties->clearScrollbarPaintOffset();
496 } 550 }
497 551
498 void PaintPropertyTreeBuilder::updateMainThreadScrollingReasons( 552 void PaintPropertyTreeBuilder::updateMainThreadScrollingReasons(
499 const LayoutObject& object, 553 const LayoutObject& object,
500 PaintPropertyTreeBuilderContext& context) { 554 PaintPropertyTreeBuilderContext& context) {
555 // TODO(pdr): Mark properties as needing an update for main thread scroll
556 // reasons and ensure reason changes are propagated to ancestors to account
557 // for the parent walk below.
501 if (context.current.scroll && 558 if (context.current.scroll &&
502 !object.document().settings()->threadedScrollingEnabled()) 559 !object.document().settings()->threadedScrollingEnabled()) {
503 context.current.scroll->addMainThreadScrollingReasons( 560 context.current.scroll->addMainThreadScrollingReasons(
504 MainThreadScrollingReason::kThreadedScrollingDisabled); 561 MainThreadScrollingReason::kThreadedScrollingDisabled);
562 }
505 563
506 if (object.isBackgroundAttachmentFixedObject()) { 564 if (object.isBackgroundAttachmentFixedObject()) {
507 auto* scrollNode = context.current.scroll; 565 auto* scrollNode = context.current.scroll;
508 while ( 566 while (
509 scrollNode && 567 scrollNode &&
510 !scrollNode->hasMainThreadScrollingReasons( 568 !scrollNode->hasMainThreadScrollingReasons(
511 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects)) { 569 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects)) {
512 scrollNode->addMainThreadScrollingReasons( 570 scrollNode->addMainThreadScrollingReasons(
513 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects); 571 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
514 scrollNode = scrollNode->parent(); 572 scrollNode = scrollNode->parent();
515 } 573 }
516 } 574 }
517 } 575 }
518 576
519 void PaintPropertyTreeBuilder::updateOverflowClip( 577 void PaintPropertyTreeBuilder::updateOverflowClip(
520 const LayoutObject& object, 578 const LayoutObject& object,
521 PaintPropertyTreeBuilderContext& context) { 579 PaintPropertyTreeBuilderContext& context) {
522 if (!object.isBox()) 580 if (!object.isBox())
523 return; 581 return;
524 const LayoutBox& box = toLayoutBox(object); 582 const LayoutBox& box = toLayoutBox(object);
583 if (object.needsPaintPropertyUpdate()) {
584 // The <input> elements can't have contents thus CSS overflow property
585 // doesn't apply. However for layout purposes we do generate child layout
586 // objects for them, e.g. button label. We should clip the overflow from
587 // those children. This is called control clip and we technically treat them
588 // like overflow clip.
589 LayoutRect clipRect;
590 if (box.hasControlClip()) {
591 clipRect = box.controlClipRect(context.current.paintOffset);
592 } else if (box.hasOverflowClip() || box.styleRef().containsPaint() ||
593 (box.isSVGRoot() &&
594 toLayoutSVGRoot(box).shouldApplyViewportClip())) {
595 clipRect = LayoutRect(pixelSnappedIntRect(
596 box.overflowClipRect(context.current.paintOffset)));
597 } else {
598 if (auto* properties = object.getMutableForPainting().paintProperties()) {
599 properties->clearInnerBorderRadiusClip();
600 properties->clearOverflowClip();
601 }
602 return;
603 }
525 604
526 // The <input> elements can't have contents thus CSS overflow property doesn't 605 const auto* currentClip = context.current.clip;
527 // apply. However for layout purposes we do generate child layout objects for 606 if (box.styleRef().hasBorderRadius()) {
528 // them, e.g. button label. We should clip the overflow from those children. 607 auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
529 // This is called control clip and we technically treat them like overflow 608 LayoutRect(context.current.paintOffset, box.size()));
530 // clip. 609 object.getMutableForPainting()
531 LayoutRect clipRect; 610 .ensurePaintProperties()
532 if (box.hasControlClip()) { 611 .updateInnerBorderRadiusClip(context.current.clip,
533 clipRect = box.controlClipRect(context.current.paintOffset); 612 context.current.transform, innerBorder);
534 } else if (box.hasOverflowClip() || box.styleRef().containsPaint() || 613 currentClip = object.paintProperties()->innerBorderRadiusClip();
535 (box.isSVGRoot() && 614 } else if (auto* properties =
536 toLayoutSVGRoot(box).shouldApplyViewportClip())) { 615 object.getMutableForPainting().paintProperties()) {
537 clipRect = LayoutRect(
538 pixelSnappedIntRect(box.overflowClipRect(context.current.paintOffset)));
539 } else {
540 if (auto* properties = object.getMutableForPainting().paintProperties()) {
541 properties->clearInnerBorderRadiusClip(); 616 properties->clearInnerBorderRadiusClip();
542 properties->clearOverflowClip();
543 } 617 }
544 return; 618
619 object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
620 currentClip, context.current.transform,
621 FloatRoundedRect(FloatRect(clipRect)));
545 } 622 }
546 623
547 if (box.styleRef().hasBorderRadius()) { 624 const auto* properties = object.paintProperties();
548 auto innerBorder = box.styleRef().getRoundedInnerBorderFor( 625 if (properties && properties->overflowClip())
549 LayoutRect(context.current.paintOffset, box.size())); 626 context.current.clip = properties->overflowClip();
550 context.current.clip =
551 object.getMutableForPainting()
552 .ensurePaintProperties()
553 .updateInnerBorderRadiusClip(
554 context.current.clip, context.current.transform, innerBorder);
555 } else if (auto* properties =
556 object.getMutableForPainting().paintProperties()) {
557 properties->clearInnerBorderRadiusClip();
558 }
559
560 context.current.clip =
561 object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
562 context.current.clip, context.current.transform,
563 FloatRoundedRect(FloatRect(clipRect)));
564 } 627 }
565 628
566 static FloatPoint perspectiveOrigin(const LayoutBox& box) { 629 static FloatPoint perspectiveOrigin(const LayoutBox& box) {
567 const ComputedStyle& style = box.styleRef(); 630 const ComputedStyle& style = box.styleRef();
568 FloatSize borderBoxSize(box.size()); 631 FloatSize borderBoxSize(box.size());
569 return FloatPoint( 632 return FloatPoint(
570 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), 633 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()),
571 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); 634 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height()));
572 } 635 }
573 636
574 void PaintPropertyTreeBuilder::updatePerspective( 637 void PaintPropertyTreeBuilder::updatePerspective(
575 const LayoutObject& object, 638 const LayoutObject& object,
576 PaintPropertyTreeBuilderContext& context) { 639 PaintPropertyTreeBuilderContext& context) {
577 const ComputedStyle& style = object.styleRef(); 640 if (object.needsPaintPropertyUpdate()) {
578 if (!object.isBox() || !style.hasPerspective()) { 641 const ComputedStyle& style = object.styleRef();
579 if (auto* properties = object.getMutableForPainting().paintProperties()) 642 if (object.isBox() && style.hasPerspective()) {
580 properties->clearPerspective(); 643 // The perspective node must not flatten (else nothing will get
581 return; 644 // perspective), but it should still extend the rendering context as
582 } 645 // most transform nodes do.
583 646 TransformationMatrix matrix =
584 // The perspective node must not flatten (else nothing will get 647 TransformationMatrix().applyPerspective(style.perspective());
585 // perspective), but it should still extend the rendering context as most 648 FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
586 // transform nodes do. 649 toLayoutSize(context.current.paintOffset);
587 TransformationMatrix matrix =
588 TransformationMatrix().applyPerspective(style.perspective());
589 FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
590 toLayoutSize(context.current.paintOffset);
591 context.current.transform =
592 object.getMutableForPainting().ensurePaintProperties().updatePerspective( 650 object.getMutableForPainting().ensurePaintProperties().updatePerspective(
593 context.current.transform, matrix, origin, 651 context.current.transform, matrix, origin,
594 context.current.shouldFlattenInheritedTransform, 652 context.current.shouldFlattenInheritedTransform,
595 context.current.renderingContextID); 653 context.current.renderingContextID);
596 context.current.shouldFlattenInheritedTransform = false; 654 } else {
655 if (auto* properties = object.getMutableForPainting().paintProperties())
656 properties->clearPerspective();
657 }
658 }
659
660 const auto* properties = object.paintProperties();
661 if (properties && properties->perspective()) {
662 context.current.transform = properties->perspective();
663 context.current.shouldFlattenInheritedTransform = false;
664 }
597 } 665 }
598 666
599 void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform( 667 void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform(
600 const LayoutObject& object, 668 const LayoutObject& object,
601 PaintPropertyTreeBuilderContext& context) { 669 PaintPropertyTreeBuilderContext& context) {
602 if (!object.isSVGRoot()) 670 if (!object.isSVGRoot())
603 return; 671 return;
604 672
605 AffineTransform transformToBorderBox = 673 if (object.needsPaintPropertyUpdate()) {
606 SVGRootPainter(toLayoutSVGRoot(object)) 674 AffineTransform transformToBorderBox =
607 .transformToPixelSnappedBorderBox(context.current.paintOffset); 675 SVGRootPainter(toLayoutSVGRoot(object))
608 676 .transformToPixelSnappedBorderBox(context.current.paintOffset);
609 // The paint offset is included in |transformToBorderBox| so SVG does not need 677 if (!transformToBorderBox.isIdentity()) {
610 // to handle paint offset internally.
611 context.current.paintOffset = LayoutPoint();
612
613 if (transformToBorderBox.isIdentity()) {
614 if (auto* properties = object.getMutableForPainting().paintProperties())
615 properties->clearSvgLocalToBorderBoxTransform();
616 return;
617 }
618
619 context.current.transform =
620 object.getMutableForPainting() 678 object.getMutableForPainting()
621 .ensurePaintProperties() 679 .ensurePaintProperties()
622 .updateSvgLocalToBorderBoxTransform( 680 .updateSvgLocalToBorderBoxTransform(
623 context.current.transform, transformToBorderBox, FloatPoint3D()); 681 context.current.transform, transformToBorderBox, FloatPoint3D());
624 context.current.shouldFlattenInheritedTransform = false; 682 } else {
625 context.current.renderingContextID = 0; 683 if (auto* properties = object.getMutableForPainting().paintProperties())
684 properties->clearSvgLocalToBorderBoxTransform();
685 }
686 }
687
688 const auto* properties = object.paintProperties();
689 if (properties && properties->svgLocalToBorderBoxTransform()) {
690 context.current.transform = properties->svgLocalToBorderBoxTransform();
691 context.current.shouldFlattenInheritedTransform = false;
692 context.current.renderingContextID = 0;
693 }
694 // The paint offset is included in |transformToBorderBox| so SVG does not need
695 // to handle paint offset internally.
696 context.current.paintOffset = LayoutPoint();
626 } 697 }
627 698
628 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation( 699 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation(
629 const LayoutObject& object, 700 const LayoutObject& object,
630 PaintPropertyTreeBuilderContext& context) { 701 PaintPropertyTreeBuilderContext& context) {
631 if (object.hasOverflowClip()) { 702 if (object.needsPaintPropertyUpdate()) {
632 const LayoutBox& box = toLayoutBox(object); 703 if (object.hasOverflowClip()) {
633 const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea(); 704 const LayoutBox& box = toLayoutBox(object);
634 IntSize scrollOffset = box.scrolledContentOffset(); 705 const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
635 if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) { 706 IntSize scrollOffset = box.scrolledContentOffset();
636 TransformationMatrix matrix = TransformationMatrix().translate( 707 if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
637 -scrollOffset.width(), -scrollOffset.height()); 708 TransformationMatrix matrix = TransformationMatrix().translate(
638 context.current.transform = 709 -scrollOffset.width(), -scrollOffset.height());
639 object.getMutableForPainting() 710 object.getMutableForPainting()
640 .ensurePaintProperties() 711 .ensurePaintProperties()
641 .updateScrollTranslation( 712 .updateScrollTranslation(
642 context.current.transform, matrix, FloatPoint3D(), 713 context.current.transform, matrix, FloatPoint3D(),
643 context.current.shouldFlattenInheritedTransform, 714 context.current.shouldFlattenInheritedTransform,
644 context.current.renderingContextID); 715 context.current.renderingContextID);
645 716
646 IntSize scrollClip = scrollableArea->visibleContentRect().size(); 717 IntSize scrollClip = scrollableArea->visibleContentRect().size();
647 IntSize scrollBounds = scrollableArea->contentsSize(); 718 IntSize scrollBounds = scrollableArea->contentsSize();
648 bool userScrollableHorizontal = 719 bool userScrollableHorizontal =
649 scrollableArea->userInputScrollable(HorizontalScrollbar); 720 scrollableArea->userInputScrollable(HorizontalScrollbar);
650 bool userScrollableVertical = 721 bool userScrollableVertical =
651 scrollableArea->userInputScrollable(VerticalScrollbar); 722 scrollableArea->userInputScrollable(VerticalScrollbar);
652 context.current.scroll = 723 object.getMutableForPainting().ensurePaintProperties().updateScroll(
653 object.getMutableForPainting().ensurePaintProperties().updateScroll( 724 context.current.scroll,
654 context.current.scroll, context.current.transform, scrollClip, 725 object.paintProperties()->scrollTranslation(), scrollClip,
655 scrollBounds, userScrollableHorizontal, userScrollableVertical); 726 scrollBounds, userScrollableHorizontal, userScrollableVertical);
656 727 } else {
657 context.current.shouldFlattenInheritedTransform = false; 728 // Ensure pre-existing properties are cleared when there is no
658 return; 729 // scrolling.
730 auto* properties = object.getMutableForPainting().paintProperties();
731 if (properties) {
732 properties->clearScrollTranslation();
733 properties->clearScroll();
734 }
735 }
659 } 736 }
660 } 737 }
661 738
662 if (auto* properties = object.getMutableForPainting().paintProperties()) { 739 if (object.paintProperties() && object.paintProperties()->scroll()) {
663 properties->clearScrollTranslation(); 740 context.current.transform = object.paintProperties()->scrollTranslation();
664 properties->clearScroll(); 741 const auto* scroll = object.paintProperties()->scroll();
742 // TODO(pdr): Remove this const cast.
743 context.current.scroll = const_cast<ScrollPaintPropertyNode*>(scroll);
744 context.current.shouldFlattenInheritedTransform = false;
665 } 745 }
666 } 746 }
667 747
668 void PaintPropertyTreeBuilder::updateOutOfFlowContext( 748 void PaintPropertyTreeBuilder::updateOutOfFlowContext(
669 const LayoutObject& object, 749 const LayoutObject& object,
670 PaintPropertyTreeBuilderContext& context) { 750 PaintPropertyTreeBuilderContext& context) {
671 if (object.canContainAbsolutePositionObjects()) { 751 if (object.canContainAbsolutePositionObjects()) {
672 context.absolutePosition = context.current; 752 context.absolutePosition = context.current;
673 context.containerForAbsolutePosition = &object; 753 context.containerForAbsolutePosition = &object;
674 } 754 }
(...skipping 19 matching lines...) Expand all
694 // absolute position container. However for fixed-position descendants we 774 // absolute position container. However for fixed-position descendants we
695 // need to insert the clip here if we are not a containing block ancestor of 775 // need to insert the clip here if we are not a containing block ancestor of
696 // them. 776 // them.
697 auto* cssClip = object.getMutableForPainting().paintProperties()->cssClip(); 777 auto* cssClip = object.getMutableForPainting().paintProperties()->cssClip();
698 778
699 // Before we actually create anything, check whether in-flow context and 779 // Before we actually create anything, check whether in-flow context and
700 // fixed-position context has exactly the same clip. Reuse if possible. 780 // fixed-position context has exactly the same clip. Reuse if possible.
701 if (context.fixedPosition.clip == cssClip->parent()) { 781 if (context.fixedPosition.clip == cssClip->parent()) {
702 context.fixedPosition.clip = cssClip; 782 context.fixedPosition.clip = cssClip;
703 } else { 783 } else {
704 context.fixedPosition.clip = 784 if (object.needsPaintPropertyUpdate()) {
705 object.getMutableForPainting() 785 object.getMutableForPainting()
706 .ensurePaintProperties() 786 .ensurePaintProperties()
707 .updateCssClipFixedPosition( 787 .updateCssClipFixedPosition(context.fixedPosition.clip,
708 context.fixedPosition.clip, 788 const_cast<TransformPaintPropertyNode*>(
709 const_cast<TransformPaintPropertyNode*>( 789 cssClip->localTransformSpace()),
710 cssClip->localTransformSpace()), 790 cssClip->clipRect());
711 cssClip->clipRect()); 791 }
792 const auto* properties = object.paintProperties();
793 if (properties && properties->cssClipFixedPosition())
794 context.fixedPosition.clip = properties->cssClipFixedPosition();
712 return; 795 return;
713 } 796 }
714 } 797 }
715 798
716 if (auto* properties = object.getMutableForPainting().paintProperties()) 799 if (object.needsPaintPropertyUpdate()) {
717 properties->clearCssClipFixedPosition(); 800 if (auto* properties = object.getMutableForPainting().paintProperties())
801 properties->clearCssClipFixedPosition();
802 }
718 } 803 }
719 804
720 // Override ContainingBlockContext based on the properties of a containing block 805 // Override ContainingBlockContext based on the properties of a containing block
721 // that was previously walked in a subtree other than the current subtree being 806 // that was previously walked in a subtree other than the current subtree being
722 // walked. Used for out-of-flow positioned descendants of multi-column spanner 807 // walked. Used for out-of-flow positioned descendants of multi-column spanner
723 // when the containing block is not in the normal tree walk order. 808 // when the containing block is not in the normal tree walk order.
724 // For example: 809 // For example:
725 // <div id="columns" style="columns: 2"> 810 // <div id="columns" style="columns: 2">
726 // <div id="relative" style="position: relative"> 811 // <div id="relative" style="position: relative">
727 // <div id="spanner" style="column-span: all"> 812 // <div id="spanner" style="column-span: all">
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
832 // Similar adjustment is done in LayoutTableCell::offsetFromContainer(). 917 // Similar adjustment is done in LayoutTableCell::offsetFromContainer().
833 if (boxModelObject.isTableCell()) { 918 if (boxModelObject.isTableCell()) {
834 LayoutObject* parentRow = boxModelObject.parent(); 919 LayoutObject* parentRow = boxModelObject.parent();
835 ASSERT(parentRow && parentRow->isTableRow()); 920 ASSERT(parentRow && parentRow->isTableRow());
836 context.current.paintOffset.moveBy( 921 context.current.paintOffset.moveBy(
837 -toLayoutBox(parentRow)->topLeftLocation()); 922 -toLayoutBox(parentRow)->topLeftLocation());
838 } 923 }
839 } 924 }
840 } 925 }
841 926
842 void PaintPropertyTreeBuilder::buildTreeNodesForSelf( 927 void PaintPropertyTreeBuilder::updatePropertiesForSelf(
843 const LayoutObject& object, 928 const LayoutObject& object,
844 PaintPropertyTreeBuilderContext& context) { 929 PaintPropertyTreeBuilderContext& context) {
845 if (!object.isBoxModelObject() && !object.isSVG()) 930 if (!object.isBoxModelObject() && !object.isSVG())
846 return; 931 return;
847 932
933 #if DCHECK_IS_ON()
934 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object);
935 #endif
936
848 deriveBorderBoxFromContainerContext(object, context); 937 deriveBorderBoxFromContainerContext(object, context);
849 938
850 updatePaintOffsetTranslation(object, context); 939 updatePaintOffsetTranslation(object, context);
851 updateTransform(object, context); 940 updateTransform(object, context);
852 updateEffect(object, context); 941 updateEffect(object, context);
853 updateCssClip(object, context); 942 updateCssClip(object, context);
854 updateLocalBorderBoxContext(object, context); 943 updateLocalBorderBoxContext(object, context);
855 updateScrollbarPaintOffset(object, context); 944 updateScrollbarPaintOffset(object, context);
856 updateMainThreadScrollingReasons(object, context); 945 updateMainThreadScrollingReasons(object, context);
857 } 946 }
858 947
859 void PaintPropertyTreeBuilder::buildTreeNodesForChildren( 948 void PaintPropertyTreeBuilder::updatePropertiesForChildren(
860 const LayoutObject& object, 949 const LayoutObject& object,
861 PaintPropertyTreeBuilderContext& context) { 950 PaintPropertyTreeBuilderContext& context) {
862 if (!object.isBoxModelObject() && !object.isSVG()) 951 if (!object.isBoxModelObject() && !object.isSVG())
863 return; 952 return;
864 953
954 #if DCHECK_IS_ON()
955 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object);
956 #endif
957
865 updateOverflowClip(object, context); 958 updateOverflowClip(object, context);
866 updatePerspective(object, context); 959 updatePerspective(object, context);
867 updateSvgLocalToBorderBoxTransform(object, context); 960 updateSvgLocalToBorderBoxTransform(object, context);
868 updateScrollAndScrollTranslation(object, context); 961 updateScrollAndScrollTranslation(object, context);
869 updateOutOfFlowContext(object, context); 962 updateOutOfFlowContext(object, context);
870 } 963 }
871 964
872 } // namespace blink 965 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698