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