| 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/PrePaintTreeWalk.h" |    5 #include "core/paint/PrePaintTreeWalk.h" | 
|    6  |    6  | 
|    7 #include "core/dom/DocumentLifecycle.h" |    7 #include "core/dom/DocumentLifecycle.h" | 
|    8 #include "core/frame/FrameView.h" |    8 #include "core/frame/FrameView.h" | 
|    9 #include "core/frame/LocalFrame.h" |    9 #include "core/frame/LocalFrame.h" | 
|   10 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h" |   10 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.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  |   13  | 
|   14 namespace blink { |   14 namespace blink { | 
|   15  |   15  | 
|   16 struct PrePaintTreeWalkContext { |   16 struct PrePaintTreeWalkContext { | 
|   17   PrePaintTreeWalkContext() : paintInvalidatorContext(treeBuilderContext) {} |   17   PrePaintTreeWalkContext() : paintInvalidatorContext(treeBuilderContext) {} | 
|   18   PrePaintTreeWalkContext(const PrePaintTreeWalkContext& parentContext) |   18   PrePaintTreeWalkContext(const PrePaintTreeWalkContext& parentContext) | 
|   19       : treeBuilderContext(parentContext.treeBuilderContext), |   19       : treeBuilderContext(parentContext.treeBuilderContext), | 
|   20         paintInvalidatorContext(treeBuilderContext, |   20         paintInvalidatorContext(treeBuilderContext, | 
|   21                                 parentContext.paintInvalidatorContext) {} |   21                                 parentContext.paintInvalidatorContext) {} | 
|   22  |   22  | 
|   23   bool needToUpdatePaintPropertySubtree = false; |  | 
|   24   PaintPropertyTreeBuilderContext treeBuilderContext; |   23   PaintPropertyTreeBuilderContext treeBuilderContext; | 
|   25   PaintInvalidatorContext paintInvalidatorContext; |   24   PaintInvalidatorContext paintInvalidatorContext; | 
|   26 }; |   25 }; | 
|   27  |   26  | 
|   28 void PrePaintTreeWalk::walk(FrameView& rootFrame) { |   27 void PrePaintTreeWalk::walk(FrameView& rootFrame) { | 
|   29   DCHECK(rootFrame.frame().document()->lifecycle().state() == |   28   DCHECK(rootFrame.frame().document()->lifecycle().state() == | 
|   30          DocumentLifecycle::InPrePaint); |   29          DocumentLifecycle::InPrePaint); | 
|   31  |   30  | 
|   32   PrePaintTreeWalkContext initialContext; |   31   PrePaintTreeWalkContext initialContext; | 
|   33   initialContext.treeBuilderContext = |   32   initialContext.treeBuilderContext = | 
|   34       m_propertyTreeBuilder.setupInitialContext(); |   33       m_propertyTreeBuilder.setupInitialContext(); | 
|   35   walk(rootFrame, initialContext); |   34   walk(rootFrame, initialContext); | 
|   36   m_paintInvalidator.processPendingDelayedPaintInvalidations(); |   35   m_paintInvalidator.processPendingDelayedPaintInvalidations(); | 
|   37 } |   36 } | 
|   38  |   37  | 
|   39 void PrePaintTreeWalk::walk(FrameView& frameView, |   38 bool PrePaintTreeWalk::walk(FrameView& frameView, | 
|   40                             const PrePaintTreeWalkContext& context) { |   39                             const PrePaintTreeWalkContext& context) { | 
|   41   if (frameView.shouldThrottleRendering()) |   40   if (frameView.shouldThrottleRendering()) { | 
|   42     return; |   41     // The walk was interrupted by throttled rendering so this subtree was not | 
 |   42     // fully updated. | 
 |   43     return false; | 
 |   44   } | 
 |   45  | 
 |   46   PrePaintTreeWalkContext localContext(context); | 
 |   47   m_propertyTreeBuilder.updateProperties(frameView, | 
 |   48                                          localContext.treeBuilderContext); | 
 |   49   m_paintInvalidator.invalidatePaintIfNeeded( | 
 |   50       frameView, localContext.paintInvalidatorContext); | 
 |   51  | 
 |   52   LayoutView* view = frameView.layoutView(); | 
 |   53   bool descendantsFullyUpdated = view ? walk(*view, localContext) : true; | 
 |   54   if (descendantsFullyUpdated) { | 
 |   55 #if DCHECK_IS_ON() | 
 |   56     frameView.layoutView()->assertSubtreeClearedPaintInvalidationFlags(); | 
 |   57 #endif | 
 |   58     // If descendants were not fully updated, do not clear flags. During the | 
 |   59     // next PrePaintTreeWalk, these flags will be used again. | 
 |   60     frameView.clearNeedsPaintPropertyUpdate(); | 
 |   61   } | 
 |   62   return descendantsFullyUpdated; | 
 |   63 } | 
 |   64  | 
 |   65 bool PrePaintTreeWalk::walk(const LayoutObject& object, | 
 |   66                             const PrePaintTreeWalkContext& context) { | 
 |   67   // Early out from the treewalk if possible. | 
 |   68   if (!object.needsPaintPropertyUpdate() && | 
 |   69       !object.descendantNeedsPaintPropertyUpdate() && | 
 |   70       !context.treeBuilderContext.forceSubtreeUpdate && | 
 |   71       !context.paintInvalidatorContext.forcedSubtreeInvalidationFlags && | 
 |   72       !object | 
 |   73            .shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState())
      { | 
 |   74     // Even though the subtree was not walked, we know that a walk will not | 
 |   75     // change anything and can return true as if the subtree was fully updated. | 
 |   76     return true; | 
 |   77   } | 
|   43  |   78  | 
|   44   PrePaintTreeWalkContext localContext(context); |   79   PrePaintTreeWalkContext localContext(context); | 
|   45  |   80  | 
|   46   // Check whether we need to update the paint property trees. |   81   // TODO(pdr): These should be removable once paint offset changes mark an | 
|   47   if (!localContext.needToUpdatePaintPropertySubtree) { |   82   // object as needing a paint property update. Below, we temporarily re-use | 
|   48     if (context.paintInvalidatorContext.forcedSubtreeInvalidationFlags) { |   83   // paint invalidation flags to detect paint offset changes. | 
|   49       // forcedSubtreeInvalidationFlags will be true if locations have changed |   84   if (localContext.paintInvalidatorContext.forcedSubtreeInvalidationFlags) { | 
|   50       // which will affect paint properties (e.g., PaintOffset). |   85     // forcedSubtreeInvalidationFlags will be true if locations have changed | 
|   51       localContext.needToUpdatePaintPropertySubtree = true; |   86     // which will affect paint properties (e.g., PaintOffset). | 
|   52     } else if (frameView.needsPaintPropertyUpdate()) { |   87     localContext.treeBuilderContext.forceSubtreeUpdate = true; | 
|   53       localContext.needToUpdatePaintPropertySubtree = true; |   88   } else if (object.shouldDoFullPaintInvalidation()) { | 
|   54     } |   89     // shouldDoFullPaintInvalidation will be true when locations or overflow | 
 |   90     // changes which will affect paint properties (e.g., PaintOffset, scroll). | 
 |   91     object.getMutableForPainting().setNeedsPaintPropertyUpdate(); | 
 |   92   } else if (object.mayNeedPaintInvalidation()) { | 
 |   93     // mayNeedpaintInvalidation will be true when locations change which will | 
 |   94     // affect paint properties (e.g., PaintOffset). | 
 |   95     object.getMutableForPainting().setNeedsPaintPropertyUpdate(); | 
|   55   } |   96   } | 
|   56   // Paint properties can depend on their ancestor properties so ensure the |  | 
|   57   // entire subtree is rebuilt on any changes. |  | 
|   58   // TODO(pdr): Add additional granularity to the needs update approach such as |  | 
|   59   // the ability to do local updates that don't change the subtree. |  | 
|   60   if (localContext.needToUpdatePaintPropertySubtree) |  | 
|   61     frameView.setNeedsPaintPropertyUpdate(); |  | 
|   62  |  | 
|   63   m_propertyTreeBuilder.updateProperties(frameView, |  | 
|   64                                          localContext.treeBuilderContext); |  | 
|   65  |  | 
|   66   m_paintInvalidator.invalidatePaintIfNeeded( |  | 
|   67       frameView, localContext.paintInvalidatorContext); |  | 
|   68  |  | 
|   69   if (LayoutView* layoutView = frameView.layoutView()) |  | 
|   70     walk(*layoutView, localContext); |  | 
|   71  |  | 
|   72 #if DCHECK_IS_ON() |  | 
|   73   frameView.layoutView()->assertSubtreeClearedPaintInvalidationFlags(); |  | 
|   74 #endif |  | 
|   75  |  | 
|   76   frameView.clearNeedsPaintPropertyUpdate(); |  | 
|   77 } |  | 
|   78  |  | 
|   79 void PrePaintTreeWalk::walk(const LayoutObject& object, |  | 
|   80                             const PrePaintTreeWalkContext& context) { |  | 
|   81   PrePaintTreeWalkContext localContext(context); |  | 
|   82  |  | 
|   83   // Check whether we need to update the paint property trees. |  | 
|   84   if (!localContext.needToUpdatePaintPropertySubtree) { |  | 
|   85     if (context.paintInvalidatorContext.forcedSubtreeInvalidationFlags) { |  | 
|   86       // forcedSubtreeInvalidationFlags will be true if locations have changed |  | 
|   87       // which will affect paint properties (e.g., PaintOffset). |  | 
|   88       localContext.needToUpdatePaintPropertySubtree = true; |  | 
|   89     } else if (object.needsPaintPropertyUpdate()) { |  | 
|   90       localContext.needToUpdatePaintPropertySubtree = true; |  | 
|   91     } else if (object.mayNeedPaintInvalidation()) { |  | 
|   92       // mayNeedpaintInvalidation will be true when locations change which will |  | 
|   93       // affect paint properties (e.g., PaintOffset). |  | 
|   94       localContext.needToUpdatePaintPropertySubtree = true; |  | 
|   95     } else if (object.shouldDoFullPaintInvalidation()) { |  | 
|   96       // shouldDoFullPaintInvalidation will be true when locations or overflow |  | 
|   97       // changes which will affect paint properties (e.g., PaintOffset, scroll). |  | 
|   98       localContext.needToUpdatePaintPropertySubtree = true; |  | 
|   99     } |  | 
|  100   } |  | 
|  101  |  | 
|  102   // Paint properties can depend on their ancestor properties so ensure the |  | 
|  103   // entire subtree is rebuilt on any changes. |  | 
|  104   // TODO(pdr): Add additional granularity to the needs update approach such as |  | 
|  105   // the ability to do local updates that don't change the subtree. |  | 
|  106   if (localContext.needToUpdatePaintPropertySubtree) |  | 
|  107     object.getMutableForPainting().setNeedsPaintPropertyUpdate(); |  | 
|  108  |   97  | 
|  109   // TODO(pdr): Ensure multi column works with incremental property tree |   98   // TODO(pdr): Ensure multi column works with incremental property tree | 
|  110   // construction. |   99   // construction. | 
|  111   if (object.isLayoutMultiColumnSpannerPlaceholder()) { |  100   if (object.isLayoutMultiColumnSpannerPlaceholder()) { | 
|  112     // Walk multi-column spanner as if it replaces the placeholder. |  101     // Walk multi-column spanner as if it replaces the placeholder. | 
|  113     // Set the flag so that the tree builder can specially handle out-of-flow |  102     // Set the flag so that the tree builder can specially handle out-of-flow | 
|  114     // positioned descendants if their containers are between the multi-column |  103     // positioned descendants if their containers are between the multi-column | 
|  115     // container and the spanner. See PaintPropertyTreeBuilder for details. |  104     // container and the spanner. See PaintPropertyTreeBuilder for details. | 
|  116     localContext.treeBuilderContext.isUnderMultiColumnSpanner = true; |  105     localContext.treeBuilderContext.isUnderMultiColumnSpanner = true; | 
|  117     walk(*toLayoutMultiColumnSpannerPlaceholder(object) |  106     bool descendantsFullyUpdated = | 
|  118               .layoutObjectInFlowThread(), |  107         walk(*toLayoutMultiColumnSpannerPlaceholder(object) | 
|  119          localContext); |  108                   .layoutObjectInFlowThread(), | 
|  120     object.getMutableForPainting().clearPaintInvalidationFlags(); |  109              localContext); | 
|  121     object.getMutableForPainting().clearNeedsPaintPropertyUpdate(); |  110     if (descendantsFullyUpdated) { | 
|  122     object.getMutableForPainting().clearDescendantNeedsPaintPropertyUpdate(); |  111       // If descendants were not fully updated, do not clear flags. During the | 
|  123     return; |  112       // next PrePaintTreeWalk, these flags will be used again. | 
 |  113       object.getMutableForPainting().clearPaintInvalidationFlags(); | 
 |  114       object.getMutableForPainting().clearNeedsPaintPropertyUpdate(); | 
 |  115       object.getMutableForPainting().clearDescendantNeedsPaintPropertyUpdate(); | 
 |  116     } | 
 |  117     return descendantsFullyUpdated; | 
|  124   } |  118   } | 
|  125  |  119  | 
|  126   m_propertyTreeBuilder.updatePropertiesForSelf( |  120   m_propertyTreeBuilder.updatePropertiesForSelf( | 
|  127       object, localContext.treeBuilderContext); |  121       object, localContext.treeBuilderContext); | 
|  128   m_paintInvalidator.invalidatePaintIfNeeded( |  122   m_paintInvalidator.invalidatePaintIfNeeded( | 
|  129       object, localContext.paintInvalidatorContext); |  123       object, localContext.paintInvalidatorContext); | 
|  130   m_propertyTreeBuilder.updatePropertiesForChildren( |  124   m_propertyTreeBuilder.updatePropertiesForChildren( | 
|  131       object, localContext.treeBuilderContext); |  125       object, localContext.treeBuilderContext); | 
|  132  |  126  | 
 |  127   bool descendantsFullyUpdated = true; | 
|  133   for (const LayoutObject* child = object.slowFirstChild(); child; |  128   for (const LayoutObject* child = object.slowFirstChild(); child; | 
|  134        child = child->nextSibling()) { |  129        child = child->nextSibling()) { | 
|  135     // Column spanners are walked through their placeholders. See above. |  130     // Column spanners are walked through their placeholders. See above. | 
|  136     if (child->isColumnSpanAll()) |  131     if (child->isColumnSpanAll()) | 
|  137       continue; |  132       continue; | 
|  138     walk(*child, localContext); |  133     bool childFullyUpdated = walk(*child, localContext); | 
 |  134     if (!childFullyUpdated) | 
 |  135       descendantsFullyUpdated = false; | 
|  139   } |  136   } | 
|  140  |  137  | 
|  141   if (object.isLayoutPart()) { |  138   if (object.isLayoutPart()) { | 
|  142     const LayoutPart& layoutPart = toLayoutPart(object); |  139     const LayoutPart& layoutPart = toLayoutPart(object); | 
|  143     Widget* widget = layoutPart.widget(); |  140     Widget* widget = layoutPart.widget(); | 
|  144     if (widget && widget->isFrameView()) { |  141     if (widget && widget->isFrameView()) { | 
|  145       localContext.treeBuilderContext.current.paintOffset += |  142       localContext.treeBuilderContext.current.paintOffset += | 
|  146           layoutPart.replacedContentRect().location() - |  143           layoutPart.replacedContentRect().location() - | 
|  147           widget->frameRect().location(); |  144           widget->frameRect().location(); | 
|  148       localContext.treeBuilderContext.current.paintOffset = |  145       localContext.treeBuilderContext.current.paintOffset = | 
|  149           roundedIntPoint(localContext.treeBuilderContext.current.paintOffset); |  146           roundedIntPoint(localContext.treeBuilderContext.current.paintOffset); | 
|  150       walk(*toFrameView(widget), localContext); |  147       bool frameFullyUpdated = walk(*toFrameView(widget), localContext); | 
 |  148       if (!frameFullyUpdated) | 
 |  149         descendantsFullyUpdated = false; | 
|  151     } |  150     } | 
|  152     // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). |  151     // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). | 
|  153   } |  152   } | 
|  154  |  153  | 
|  155   object.getMutableForPainting().clearPaintInvalidationFlags(); |  154   if (descendantsFullyUpdated) { | 
|  156   object.getMutableForPainting().clearNeedsPaintPropertyUpdate(); |  155     // If descendants were not updated, do not clear flags. During the next | 
|  157   object.getMutableForPainting().clearDescendantNeedsPaintPropertyUpdate(); |  156     // PrePaintTreeWalk, these flags will be used again. | 
 |  157     object.getMutableForPainting().clearPaintInvalidationFlags(); | 
 |  158     object.getMutableForPainting().clearNeedsPaintPropertyUpdate(); | 
 |  159     object.getMutableForPainting().clearDescendantNeedsPaintPropertyUpdate(); | 
 |  160   } | 
 |  161   return descendantsFullyUpdated; | 
|  158 } |  162 } | 
|  159  |  163  | 
|  160 }  // namespace blink |  164 }  // namespace blink | 
| OLD | NEW |