Index: third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp |
diff --git a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp |
index 88ef35c3a152c177b5e43fd1244ab872d89cf678..80930cebdb36b5b90b90111f5db06ad9b0e957d9 100644 |
--- a/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp |
+++ b/third_party/WebKit/Source/core/editing/CaretDisplayItemClient.cpp |
@@ -34,10 +34,11 @@ |
#include "core/layout/api/LayoutBlockItem.h" |
#include "core/layout/api/LayoutItem.h" |
#include "core/layout/api/LayoutViewItem.h" |
+#include "core/paint/ObjectPaintInvalidator.h" |
#include "core/paint/PaintInfo.h" |
+#include "core/paint/PaintInvalidator.h" |
#include "core/paint/PaintLayer.h" |
#include "platform/graphics/GraphicsContext.h" |
-#include "platform/graphics/GraphicsLayer.h" |
#include "platform/graphics/paint/DrawingRecorder.h" |
namespace blink { |
@@ -45,11 +46,11 @@ namespace blink { |
CaretDisplayItemClient::CaretDisplayItemClient() = default; |
CaretDisplayItemClient::~CaretDisplayItemClient() = default; |
-static inline bool caretRendersInsideNode(Node* node) { |
+static inline bool caretRendersInsideNode(const Node* node) { |
return node && !isDisplayInsideTable(node) && !editingIgnoresContent(*node); |
} |
-LayoutBlock* CaretDisplayItemClient::caretLayoutObject(Node* node) { |
+LayoutBlock* CaretDisplayItemClient::caretLayoutBlock(const Node* node) { |
if (!node) |
return nullptr; |
@@ -107,54 +108,136 @@ LayoutRect CaretDisplayItemClient::computeCaretRect( |
// Get the layoutObject that will be responsible for painting the caret |
// (which is either the layoutObject we just found, or one of its containers). |
LayoutBlockItem caretPainterItem = |
- LayoutBlockItem(caretLayoutObject(caretPosition.anchorNode())); |
+ LayoutBlockItem(caretLayoutBlock(caretPosition.anchorNode())); |
return mapCaretRectToCaretPainter(LayoutItem(layoutObject), caretPainterItem, |
caretLocalRect); |
} |
-// TODO(yoichio): |node| is FrameSelection::m_previousCaretNode and this is bad |
-// design. We should use only previous layoutObject or Rectangle to invalidate |
-// old caret. |
-void CaretDisplayItemClient::invalidateLocalCaretRect(Node* node, |
- const LayoutRect& rect) { |
- LayoutBlock* caretLayoutBlock = caretLayoutObject(node); |
- if (!caretLayoutBlock) |
+void CaretDisplayItemClient::updateStyleAndLayoutIfNeeded( |
+ const PositionWithAffinity& caretPosition) { |
+ LayoutBlock* newLayoutBlock = caretLayoutBlock(caretPosition.anchorNode()); |
+ if (newLayoutBlock != m_layoutBlock) { |
+ if (m_layoutBlock) |
+ m_layoutBlock->setMayNeedPaintInvalidation(); |
+ m_previousLayoutBlock = m_layoutBlock; |
+ m_layoutBlock = newLayoutBlock; |
+ m_needsPaintInvalidation = true; |
+ } else { |
+ m_previousLayoutBlock = nullptr; |
+ } |
+ |
+ if (!newLayoutBlock) { |
+ m_color = Color(); |
+ m_localRect = LayoutRect(); |
+ return; |
+ } |
+ |
+ Color newColor; |
+ if (caretPosition.anchorNode()) { |
+ newColor = caretPosition.anchorNode()->layoutObject()->resolveColor( |
+ CSSPropertyCaretColor); |
+ } |
+ if (newColor != m_color) { |
+ m_needsPaintInvalidation = true; |
+ m_color = newColor; |
+ } |
+ |
+ LayoutRect newLocalRect = computeCaretRect(caretPosition); |
+ if (newLocalRect != m_localRect) { |
+ m_needsPaintInvalidation = true; |
+ m_localRect = newLocalRect; |
+ } |
+ |
+ if (m_needsPaintInvalidation) |
+ newLayoutBlock->setMayNeedPaintInvalidation(); |
+} |
+ |
+void CaretDisplayItemClient::invalidatePaintIfNeeded( |
+ const LayoutBlock& block, |
+ const PaintInvalidatorContext& context, |
+ PaintInvalidationReason layoutBlockPaintInvalidationReason) { |
+ if (block == m_previousLayoutBlock) { |
+ // Invalidate the previous caret if it was in a different block. |
+ // m_previousLayoutBlock is set only when it's different from m_layoutBlock. |
+ DCHECK(block != m_layoutBlock); |
+ |
+ ObjectPaintInvalidatorWithContext objectInvalidator(*m_previousLayoutBlock, |
+ context); |
+ if (!isImmediateFullPaintInvalidationReason( |
+ layoutBlockPaintInvalidationReason)) { |
+ objectInvalidator.fullyInvalidatePaint(PaintInvalidationCaret, |
+ m_visualRect, LayoutRect()); |
+ } |
+ |
+ // If m_layoutBlock is not null, the following will be done when |
+ // the new caret is invalidated in m_layoutBlock. |
+ if (!m_layoutBlock) { |
+ context.paintingLayer->setNeedsRepaint(); |
+ objectInvalidator.invalidateDisplayItemClient(*this, |
+ PaintInvalidationCaret); |
+ m_visualRect = LayoutRect(); |
+ m_needsPaintInvalidation = false; |
+ } |
+ |
+ m_previousLayoutBlock = nullptr; |
+ return; |
+ } |
+ |
+ if (block != m_layoutBlock) |
return; |
- // FIXME: Need to over-paint 1 pixel to workaround some rounding problems. |
- // https://bugs.webkit.org/show_bug.cgi?id=108283 |
- LayoutRect inflatedRect = rect; |
- inflatedRect.inflate(LayoutUnit(1)); |
+ // Invalidate the new caret, and the old caret if it was in the same block. |
+ LayoutRect newVisualRect; |
+ if (m_layoutBlock && !m_localRect.isEmpty()) { |
+ newVisualRect = m_localRect; |
+ context.mapLocalRectToPaintInvalidationBacking(*m_layoutBlock, |
+ newVisualRect); |
+ newVisualRect.move(m_layoutBlock->scrollAdjustmentForPaintInvalidation( |
+ *context.paintInvalidationContainer)); |
+ |
+ if (m_layoutBlock->usesCompositedScrolling()) { |
+ // The caret should use scrolling coordinate space. |
+ DCHECK(m_layoutBlock == context.paintInvalidationContainer); |
+ newVisualRect.move(LayoutSize(m_layoutBlock->scrolledContentOffset())); |
+ } |
+ } |
+ |
+ if (m_needsPaintInvalidation || newVisualRect != m_visualRect) { |
+ m_needsPaintInvalidation = false; |
- // FIXME: We should not allow paint invalidation out of paint invalidation |
- // state. crbug.com/457415 |
- DisablePaintInvalidationStateAsserts disabler; |
+ ObjectPaintInvalidatorWithContext objectInvalidator(*m_layoutBlock, |
+ context); |
+ if (!isImmediateFullPaintInvalidationReason( |
+ layoutBlockPaintInvalidationReason)) { |
+ objectInvalidator.fullyInvalidatePaint(PaintInvalidationCaret, |
+ m_visualRect, newVisualRect); |
+ } |
+ |
+ context.paintingLayer->setNeedsRepaint(); |
+ objectInvalidator.invalidateDisplayItemClient(*this, |
+ PaintInvalidationCaret); |
+ } |
- m_visualRect = |
- node->layoutObject()->invalidatePaintRectangle(inflatedRect, this); |
+ m_visualRect = newVisualRect; |
} |
-void CaretDisplayItemClient::paintCaret(Node* node, |
- GraphicsContext& context, |
- const LayoutRect& caretLocalRect, |
- const LayoutPoint& paintOffset, |
- DisplayItem::Type displayItemType) { |
+void CaretDisplayItemClient::paintCaret( |
+ GraphicsContext& context, |
+ const LayoutPoint& paintOffset, |
+ DisplayItem::Type displayItemType) const { |
if (DrawingRecorder::useCachedDrawingIfPossible(context, *this, |
displayItemType)) |
return; |
- LayoutRect drawingRect = caretLocalRect; |
- if (LayoutBlock* layoutObject = caretLayoutObject(node)) |
- layoutObject->flipForWritingMode(drawingRect); |
+ LayoutRect drawingRect = m_localRect; |
+ m_layoutBlock->flipForWritingMode(drawingRect); |
drawingRect.moveBy(paintOffset); |
- const Color caretColor = |
- node->layoutObject()->resolveColor(CSSPropertyCaretColor); |
IntRect paintRect = pixelSnappedIntRect(drawingRect); |
DrawingRecorder drawingRecorder(context, *this, DisplayItem::kCaret, |
paintRect); |
- context.fillRect(paintRect, caretColor); |
+ context.fillRect(paintRect, m_color); |
} |
String CaretDisplayItemClient::debugName() const { |