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