Chromium Code Reviews| Index: third_party/WebKit/Source/core/editing/FrameCaret.cpp |
| diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.cpp b/third_party/WebKit/Source/core/editing/FrameCaret.cpp |
| index 2c1d4f30bf12d59b9e7c058cdbba8b87a2be4859..cdbbaa317658da7cbe0ebe598e4a340193f42035 100644 |
| --- a/third_party/WebKit/Source/core/editing/FrameCaret.cpp |
| +++ b/third_party/WebKit/Source/core/editing/FrameCaret.cpp |
| @@ -39,7 +39,6 @@ |
| #include "core/layout/LayoutTheme.h" |
| #include "core/layout/api/LayoutPartItem.h" |
| #include "core/page/Page.h" |
| -#include "core/paint/PaintLayer.h" |
| #include "public/platform/WebTraceLocation.h" |
| namespace blink { |
| @@ -50,11 +49,9 @@ FrameCaret::FrameCaret(LocalFrame& frame, |
| m_frame(frame), |
| m_caretBase(new CaretDisplayItemClient()), |
| m_caretVisibility(CaretVisibility::Hidden), |
| - m_previousCaretVisibility(CaretVisibility::Hidden), |
| m_caretBlinkTimer(TaskRunnerHelper::get(TaskType::UnspecedTimer, &frame), |
| this, |
| &FrameCaret::caretBlinkTimerFired), |
| - m_caretRectDirty(true), |
| m_shouldPaintCaret(true), |
| m_isCaretBlinkingSuspended(false), |
| m_shouldShowBlockCursor(false) {} |
| @@ -64,8 +61,6 @@ FrameCaret::~FrameCaret() = default; |
| DEFINE_TRACE(FrameCaret) { |
| visitor->trace(m_selectionEditor); |
| visitor->trace(m_frame); |
| - visitor->trace(m_previousCaretNode); |
| - visitor->trace(m_previousCaretAnchorNode); |
| SynchronousMutationObserver::trace(visitor); |
| } |
| @@ -81,7 +76,11 @@ const PositionWithAffinity FrameCaret::caretPosition() const { |
| return PositionWithAffinity(selection.start(), selection.affinity()); |
| } |
| -const DisplayItemClient& FrameCaret::displayItemClient() const { |
| +void FrameCaret::setVisualRect(const LayoutRect& r) { |
| + m_caretBase->setVisualRect(r); |
| +} |
| + |
| +const DisplayItemClient& FrameCaret::getDisplayItemClient() const { |
| return *m_caretBase; |
| } |
| @@ -121,7 +120,7 @@ void FrameCaret::updateAppearance() { |
| void FrameCaret::stopCaretBlinkTimer() { |
| if (m_caretBlinkTimer.isActive() || m_shouldPaintCaret) |
| - setCaretRectNeedsUpdate(); |
| + setNeedsPaintInvalidation(); |
| m_shouldPaintCaret = false; |
| m_caretBlinkTimer.stop(); |
| } |
| @@ -136,7 +135,7 @@ void FrameCaret::startBlinkCaret() { |
| m_caretBlinkTimer.startRepeating(blinkInterval, BLINK_FROM_HERE); |
| m_shouldPaintCaret = true; |
| - setCaretRectNeedsUpdate(); |
| + setNeedsPaintInvalidation(); |
| } |
| void FrameCaret::setCaretVisibility(CaretVisibility visibility) { |
| @@ -148,20 +147,23 @@ void FrameCaret::setCaretVisibility(CaretVisibility visibility) { |
| updateAppearance(); |
| } |
| -void FrameCaret::setCaretRectNeedsUpdate() { |
| - if (m_caretRectDirty) |
| - return; |
| - m_caretRectDirty = true; |
| +void FrameCaret::setMayNeedPaintInvalidation() { |
| + if (LayoutBlock* block = caretLayoutBlock()) |
|
yosin_UTC9
2017/01/31 20:12:58
Let's use early-return style to avoid to have (sin
|
| + block->setMayNeedPaintInvalidation(); |
| + else |
| + scheduleVisualUpdate(); |
| +} |
| +void FrameCaret::setNeedsPaintInvalidation() { |
| + if (LayoutBlock* block = caretLayoutBlock()) |
| + block->setCaretsNeedPaintInvalidation(); |
|
yosin_UTC9
2017/01/31 20:12:58
Let's use early-return style to avoid to have (sin
|
| + else |
| + scheduleVisualUpdate(); |
| +} |
| + |
| +void FrameCaret::scheduleVisualUpdate() { |
| if (Page* page = m_frame->page()) |
| page->animator().scheduleVisualUpdate(m_frame->localFrameRoot()); |
| - |
| - // Ensure the frame will be checked for paint invalidation during |
| - // PrePaintTreeWalk. |
| - if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) { |
|
chrishtr
2017/01/31 22:51:03
Why is this no longer needed?
Xianzhu
2017/02/02 23:42:06
Now block->setMayNeedPaintInvalidation() marks the
|
| - if (auto layoutItem = m_frame->ownerLayoutItem()) |
| - layoutItem.setMayNeedPaintInvalidation(); |
| - } |
| } |
| bool FrameCaret::caretPositionIsValidForDocument( |
| @@ -172,72 +174,15 @@ bool FrameCaret::caretPositionIsValidForDocument( |
| return caretPosition().document() == document && !caretPosition().isOrphan(); |
| } |
| -static bool shouldRepaintCaret(Node& node) { |
| - // If PositionAnchorType::BeforeAnchor or PositionAnchorType::AfterAnchor, |
| - // carets need to be repainted not only when the node is contentEditable but |
| - // also when its parentNode() is contentEditable. |
| - node.document().updateStyleAndLayoutTree(); |
| - return hasEditableStyle(node) || |
| - (node.parentNode() && hasEditableStyle(*node.parentNode())); |
| -} |
| - |
| -void FrameCaret::invalidateCaretRect(bool forceInvalidation) { |
| - if (!m_caretRectDirty) |
| - return; |
| - m_caretRectDirty = false; |
| - |
| - DCHECK(caretPositionIsValidForDocument(*m_frame->document())); |
| - LayoutObject* layoutObject = nullptr; |
| - LayoutRect newRect; |
| - PositionWithAffinity currentCaretPosition = caretPosition(); |
| - if (isActive()) |
| - newRect = localCaretRectOfPosition(currentCaretPosition, layoutObject); |
| - Node* newNode = layoutObject ? layoutObject->node() : nullptr; |
| - // The current selected node |newNode| could be a child multiple levels below |
| - // its associated "anchor node" ancestor, so we reference and keep around the |
| - // anchor node for checking editability. |
| - // TODO(wkorman): Consider storing previous Position, rather than Node, and |
| - // making use of EditingUtilies::isEditablePosition() directly. |
| - Node* newAnchorNode = |
| - currentCaretPosition.position().parentAnchoredEquivalent().anchorNode(); |
| - if (newNode && newAnchorNode && newNode != newAnchorNode && |
| - newAnchorNode->layoutObject() && newAnchorNode->layoutObject()->isBox()) { |
| - newNode->layoutObject()->mapToVisualRectInAncestorSpace( |
| - toLayoutBoxModelObject(newAnchorNode->layoutObject()), newRect); |
| - } |
| - // It's possible for the timer to be inactive even though we want to |
| - // invalidate the caret. For example, when running as a layout test the |
| - // caret blink interval could be zero and thus |m_caretBlinkTimer| will |
| - // never be started. We provide |forceInvalidation| for use by paint |
| - // invalidation internals where we need to invalidate the caret regardless |
| - // of timer state. |
| - if (!forceInvalidation && !m_caretBlinkTimer.isActive() && |
| - newNode == m_previousCaretNode && newRect == m_previousCaretRect && |
| - m_caretVisibility == m_previousCaretVisibility) |
| - return; |
| - |
| - if (m_previousCaretAnchorNode && |
| - shouldRepaintCaret(*m_previousCaretAnchorNode)) { |
| - m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
| - m_previousCaretRect); |
| - } |
| - if (newAnchorNode && shouldRepaintCaret(*newAnchorNode)) |
| - m_caretBase->invalidateLocalCaretRect(newAnchorNode, newRect); |
| - m_previousCaretNode = newNode; |
| - m_previousCaretAnchorNode = newAnchorNode; |
| - m_previousCaretRect = newRect; |
| - m_previousCaretVisibility = m_caretVisibility; |
| +LayoutRect FrameCaret::caretLocalRect() const { |
| + if (!isActive()) |
| + return LayoutRect(); |
| + return CaretDisplayItemClient::computeCaretRect(caretPosition()); |
| } |
| -static IntRect absoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) { |
| - LayoutBlock* caretPainter = CaretDisplayItemClient::caretLayoutObject(node); |
| - if (!caretPainter) |
| - return IntRect(); |
| - |
| - LayoutRect localRect(rect); |
| - caretPainter->flipForWritingMode(localRect); |
| - return caretPainter->localToAbsoluteQuad(FloatRect(localRect)) |
| - .enclosingBoundingBox(); |
| +LayoutBlock* FrameCaret::caretLayoutBlock() const { |
| + return CaretDisplayItemClient::caretLayoutObject( |
| + caretPosition().anchorNode()); |
| } |
| IntRect FrameCaret::absoluteCaretBounds() const { |
| @@ -247,20 +192,27 @@ IntRect FrameCaret::absoluteCaretBounds() const { |
| DocumentLifecycle::DisallowTransitionScope disallowTransition( |
| m_frame->document()->lifecycle()); |
| - Node* const caretNode = caretPosition().anchorNode(); |
| if (!isActive()) |
| - return absoluteBoundsForLocalRect(caretNode, LayoutRect()); |
| + return IntRect(); |
| + |
| + const LayoutBlock* block = caretLayoutBlock(); |
| + if (!block) |
| + return IntRect(); |
| + |
| // TODO(yosin): We should get rid of text control short path since layout |
| // tree is clean. |
| + LayoutRect localRect; |
| if (enclosingTextControl(caretPosition().position()) && |
| isVisuallyEquivalentCandidate(caretPosition().position())) { |
| - return absoluteBoundsForLocalRect( |
| - caretNode, CaretDisplayItemClient::computeCaretRect(caretPosition())); |
| + localRect = this->caretLocalRect(); |
| + } else { |
| + localRect = CaretDisplayItemClient::computeCaretRect( |
| + createVisiblePosition(caretPosition()).toPositionWithAffinity()); |
| } |
| - return absoluteBoundsForLocalRect( |
| - caretNode, |
| - CaretDisplayItemClient::computeCaretRect( |
| - createVisiblePosition(caretPosition()).toPositionWithAffinity())); |
| + |
| + block->flipForWritingMode(localRect); |
| + return block->localToAbsoluteQuad(FloatRect(localRect)) |
| + .enclosingBoundingBox(); |
| } |
| void FrameCaret::setShouldShowBlockCursor(bool shouldShowBlockCursor) { |
| @@ -279,38 +231,12 @@ void FrameCaret::paintCaret(GraphicsContext& context, |
| if (!(isActive() && m_shouldPaintCaret)) |
| return; |
| - const LayoutRect caretLocalRect = |
| - CaretDisplayItemClient::computeCaretRect(caretPosition()); |
| - m_caretBase->paintCaret(caretPosition().anchorNode(), context, caretLocalRect, |
| - paintOffset, DisplayItem::kCaret); |
| -} |
| - |
| -void FrameCaret::dataWillChange(const CharacterData& node) { |
| - if (node == m_previousCaretNode) { |
| - // This invalidation is eager, and intentionally uses stale state. |
| - DisableCompositingQueryAsserts disabler; |
| - m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
| - m_previousCaretRect); |
| - } |
| -} |
| - |
| -void FrameCaret::nodeWillBeRemoved(Node& node) { |
| - if (node != m_previousCaretNode && node != m_previousCaretAnchorNode) |
| - return; |
| - // Hits in ManualTests/caret-paint-after-last-text-is-removed.html |
| - DisableCompositingQueryAsserts disabler; |
| - m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), |
| - m_previousCaretRect); |
| - m_previousCaretNode = nullptr; |
| - m_previousCaretAnchorNode = nullptr; |
| - m_previousCaretRect = LayoutRect(); |
| - m_previousCaretVisibility = CaretVisibility::Hidden; |
| + m_caretBase->paintCaret(caretPosition().anchorNode(), context, |
| + caretLocalRect(), paintOffset, DisplayItem::kCaret); |
|
yosin_UTC9
2017/01/31 20:12:58
Yes, this is what I thought. It is redundant to ca
|
| } |
| void FrameCaret::contextDestroyed(Document*) { |
| m_caretBlinkTimer.stop(); |
| - m_previousCaretNode.clear(); |
| - m_previousCaretAnchorNode.clear(); |
| } |
| bool FrameCaret::shouldBlinkCaret() const { |
| @@ -334,7 +260,7 @@ void FrameCaret::caretBlinkTimerFired(TimerBase*) { |
| if (isCaretBlinkingSuspended() && m_shouldPaintCaret) |
| return; |
| m_shouldPaintCaret = !m_shouldPaintCaret; |
| - setCaretRectNeedsUpdate(); |
| + setNeedsPaintInvalidation(); |
| } |
| } // namespace blink |