Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "core/paint/ObjectPaintInvalidator.h" | |
| 6 | |
| 7 #include "core/layout/LayoutBlockFlow.h" | |
| 8 #include "core/paint/PaintInvalidator.h" | |
| 9 #include "core/paint/PaintLayer.h" | |
| 10 | |
| 11 namespace blink { | |
| 12 | |
| 13 typedef HashMap<const LayoutObject*, LayoutRect> SelectionPaintInvalidationMap; | |
| 14 static SelectionPaintInvalidationMap& selectionPaintInvalidationMap() | |
| 15 { | |
| 16 DEFINE_STATIC_LOCAL(SelectionPaintInvalidationMap, map, ()); | |
| 17 return map; | |
| 18 } | |
| 19 | |
| 20 static void setPreviousSelectionPaintInvalidationRect(const LayoutObject& object , const LayoutRect& rect) | |
| 21 { | |
| 22 if (rect.isEmpty()) | |
| 23 selectionPaintInvalidationMap().remove(&object); | |
| 24 else | |
| 25 selectionPaintInvalidationMap().set(&object, rect); | |
| 26 } | |
| 27 | |
| 28 void ObjectPaintInvalidator::objectWillBeDestroyed(const LayoutObject& object) | |
| 29 { | |
| 30 selectionPaintInvalidationMap().remove(&object); | |
| 31 } | |
| 32 | |
| 33 void ObjectPaintInvalidator::incrementallyInvalidatePaint() | |
| 34 { | |
| 35 const LayoutRect& oldBounds = m_context.oldBounds; | |
| 36 const LayoutRect& newBounds = m_context.newBounds; | |
| 37 | |
| 38 DCHECK(oldBounds.location() == newBounds.location()); | |
| 39 | |
| 40 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX(); | |
| 41 if (deltaRight > 0) { | |
| 42 LayoutRect invalidationRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()); | |
| 43 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta iner, invalidationRect, PaintInvalidationIncremental); | |
| 44 } else if (deltaRight < 0) { | |
| 45 LayoutRect invalidationRect(newBounds.maxX(), oldBounds.y(), -deltaRight , oldBounds.height()); | |
| 46 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta iner, invalidationRect, PaintInvalidationIncremental); | |
| 47 } | |
| 48 | |
| 49 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY(); | |
| 50 if (deltaBottom > 0) { | |
| 51 LayoutRect invalidationRect(newBounds.x(), oldBounds.maxY(), newBounds.w idth(), deltaBottom); | |
| 52 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta iner, invalidationRect, PaintInvalidationIncremental); | |
| 53 } else if (deltaBottom < 0) { | |
| 54 LayoutRect invalidationRect(oldBounds.x(), newBounds.maxY(), oldBounds.w idth(), -deltaBottom); | |
| 55 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta iner, invalidationRect, PaintInvalidationIncremental); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 void ObjectPaintInvalidator::fullyInvalidatePaint(PaintInvalidationReason reason , const LayoutRect& oldBounds, const LayoutRect& newBounds) | |
| 60 { | |
| 61 // The following logic avoids invalidating twice if one set of bounds contai ns the other. | |
| 62 if (!newBounds.contains(oldBounds)) { | |
| 63 LayoutRect invalidationRect = oldBounds; | |
| 64 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationConta iner, invalidationRect, reason); | |
| 65 | |
| 66 if (invalidationRect.contains(newBounds)) | |
| 67 return; | |
| 68 } | |
| 69 | |
| 70 m_object.invalidatePaintUsingContainer(*m_context.paintInvalidationContainer , newBounds, reason); | |
| 71 } | |
| 72 | |
| 73 PaintInvalidationReason ObjectPaintInvalidator::computePaintInvalidationReason() | |
| 74 { | |
| 75 bool boxDecorationBackgroundObscurationChanged = false; | |
|
chrishtr
2016/08/09 23:47:31
75-80 are new code?
Xianzhu
2016/08/10 16:25:01
They are previously in LayoutObject::invalidatePai
| |
| 76 bool boxDecorationBackgroundObscured = m_object.boxDecorationBackgroundIsKno wnToBeObscured(); | |
| 77 if (boxDecorationBackgroundObscured != m_object.previousBoxDecorationBackgro undObscured()) { | |
| 78 m_object.getMutableForPainting().setPreviousBoxDecorationBackgroundObscu red(boxDecorationBackgroundObscured); | |
| 79 boxDecorationBackgroundObscurationChanged = true; | |
| 80 } | |
| 81 | |
| 82 if (m_context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext::Forc edSubtreeFullInvalidation) | |
| 83 return PaintInvalidationSubtree; | |
| 84 | |
| 85 if (m_object.shouldDoFullPaintInvalidation()) | |
| 86 return m_object.fullPaintInvalidationReason(); | |
| 87 | |
| 88 if (boxDecorationBackgroundObscurationChanged) | |
| 89 return PaintInvalidationBackgroundObscurationChange; | |
| 90 | |
| 91 if (m_object.paintedOutputOfObjectHasNoEffect()) | |
| 92 return PaintInvalidationNone; | |
| 93 | |
| 94 const ComputedStyle& style = m_object.styleRef(); | |
| 95 | |
| 96 // The outline may change shape because of position change of descendants. F or simplicity, | |
| 97 // just force full paint invalidation if this object is marked for checking paint invalidation | |
| 98 // for any reason. | |
| 99 // TODO(wangxianzhu): Optimize this. | |
| 100 if (style.hasOutline()) | |
| 101 return PaintInvalidationOutline; | |
| 102 | |
| 103 bool locationChanged = m_context.newLocation != m_context.oldLocation; | |
| 104 | |
| 105 // If the bounds are the same then we know that none of the statements below | |
| 106 // can match, so we can early out. | |
| 107 if (m_context.oldBounds == m_context.newBounds) | |
| 108 return locationChanged && !m_context.oldBounds.isEmpty() ? PaintInvalida tionLocationChange : PaintInvalidationNone; | |
| 109 | |
| 110 // If we shifted, we don't know the exact reason so we are conservative and trigger a full invalidation. Shifting could | |
| 111 // be caused by some layout property (left / top) or some in-flow layoutObje ct inserted / removed before us in the tree. | |
| 112 if (m_context.newBounds.location() != m_context.oldBounds.location()) | |
| 113 return PaintInvalidationBoundsChange; | |
| 114 | |
| 115 // If the size is zero on one of our bounds then we know we're going to have | |
| 116 // to do a full invalidation of either old bounds or new bounds. | |
| 117 if (m_context.oldBounds.isEmpty()) | |
| 118 return PaintInvalidationBecameVisible; | |
| 119 if (m_context.newBounds.isEmpty()) | |
| 120 return PaintInvalidationBecameInvisible; | |
| 121 | |
| 122 if (locationChanged) | |
| 123 return PaintInvalidationLocationChange; | |
| 124 | |
| 125 return PaintInvalidationIncremental; | |
| 126 } | |
| 127 | |
| 128 void ObjectPaintInvalidator::invalidateSelectionIfNeeded(PaintInvalidationReason reason) | |
| 129 { | |
| 130 // Update selection rect when we are doing full invalidation (in case that t he object is moved, | |
| 131 // composite status changed, etc.) or shouldInvalidationSelection is set (in case that the | |
| 132 // selection itself changed). | |
| 133 bool fullInvalidation = isFullPaintInvalidationReason(reason); | |
| 134 if (!fullInvalidation && !m_object.shouldInvalidateSelection()) | |
| 135 return; | |
| 136 | |
| 137 LayoutRect oldSelectionRect = selectionPaintInvalidationMap().get(&m_object) ; | |
| 138 LayoutRect newSelectionRect = m_object.localSelectionRect(); | |
| 139 if (!newSelectionRect.isEmpty()) | |
| 140 m_context.mapLocalRectToPaintInvalidationBacking(m_object, newSelectionR ect); | |
| 141 | |
| 142 newSelectionRect.move(m_object.scrollAdjustmentForPaintInvalidation(*m_conte xt.paintInvalidationContainer)); | |
| 143 | |
| 144 setPreviousSelectionPaintInvalidationRect(m_object, newSelectionRect); | |
| 145 | |
| 146 if (!fullInvalidation) { | |
| 147 fullyInvalidatePaint(PaintInvalidationSelection, oldSelectionRect, newSe lectionRect); | |
| 148 m_context.paintingLayer->setNeedsRepaint(); | |
| 149 m_object.invalidateDisplayItemClients(PaintInvalidationSelection); | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 PaintInvalidationReason ObjectPaintInvalidator::invalidatePaintIfNeededWithCompu tedReason(PaintInvalidationReason reason) | |
| 154 { | |
| 155 // We need to invalidate the selection before checking for whether we are do ing a full invalidation. | |
| 156 // This is because we need to update the previous selection rect regardless. | |
| 157 invalidateSelectionIfNeeded(reason); | |
| 158 | |
| 159 switch (reason) { | |
| 160 case PaintInvalidationNone: | |
| 161 // TODO(trchen): Currently we don't keep track of paint offset of layout objects. | |
| 162 // There are corner cases that the display items need to be invalidated for paint offset | |
| 163 // mutation, but incurs no pixel difference (i.e. bounds stay the same) so no rect-based | |
| 164 // invalidation is issued. See crbug.com/508383 and crbug.com/515977. | |
| 165 // This is a workaround to force display items to update paint offset. | |
| 166 if (m_context.forcedSubtreeInvalidationFlags & PaintInvalidatorContext:: ForcedSubtreeInvalidationChecking) { | |
| 167 reason = PaintInvalidationLocationChange; | |
| 168 break; | |
| 169 } | |
| 170 return PaintInvalidationNone; | |
| 171 case PaintInvalidationIncremental: | |
| 172 incrementallyInvalidatePaint(); | |
| 173 break; | |
| 174 case PaintInvalidationDelayedFull: | |
| 175 return PaintInvalidationDelayedFull; | |
| 176 default: | |
| 177 DCHECK(isFullPaintInvalidationReason(reason)); | |
| 178 fullyInvalidatePaint(reason, m_context.oldBounds, m_context.newBounds); | |
| 179 } | |
| 180 | |
| 181 m_context.paintingLayer->setNeedsRepaint(); | |
| 182 m_object.invalidateDisplayItemClients(reason); | |
| 183 return reason; | |
| 184 } | |
| 185 | |
| 186 } // namespace blink | |
| OLD | NEW |