Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(748)

Unified Diff: Source/core/editing/FrameSelection.cpp

Issue 431983005: FrameSelection::updateApperance for caret should not cause layout. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Fix test failures Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/editing/FrameSelection.h ('k') | Source/core/frame/FrameView.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/editing/FrameSelection.cpp
diff --git a/Source/core/editing/FrameSelection.cpp b/Source/core/editing/FrameSelection.cpp
index 677676fb2b75bde4fd555d637189b49b96fa3b15..7427627bec55cb9841ddb15d3c94aaa91ded876f 100644
--- a/Source/core/editing/FrameSelection.cpp
+++ b/Source/core/editing/FrameSelection.cpp
@@ -96,7 +96,7 @@ FrameSelection::FrameSelection(LocalFrame* frame)
, m_observingVisibleSelection(false)
, m_granularity(CharacterGranularity)
, m_caretBlinkTimer(this, &FrameSelection::caretBlinkTimerFired)
- , m_absCaretBoundsDirty(true)
+ , m_caretRectDirty(true)
, m_caretPaint(true)
, m_isCaretBlinkingSuspended(false)
, m_focused(frame && frame->page() && frame->page()->focusController().focusedFrame() == frame)
@@ -272,11 +272,9 @@ void FrameSelection::setSelection(const VisibleSelection& newSelection, SetSelec
setFocusedNodeIfNeeded();
if (!(options & DoNotUpdateAppearance)) {
- m_frame->document()->updateLayoutIgnorePendingStylesheets();
-
// Hits in compositing/overflow/do-not-paint-outline-into-composited-scrolling-contents.html
DisableCompositingQueryAsserts disabler;
- updateAppearance();
+ updateAppearance(ResetCaretBlink);
}
// Always clear the x position used for vertical arrow navigation.
@@ -1230,70 +1228,68 @@ static bool isTextFormControl(const VisibleSelection& selection)
return enclosingTextFormControl(selection.start());
}
-LayoutRect FrameSelection::localCaretRect()
+IntRect FrameSelection::absoluteCaretBounds()
{
- if (shouldUpdateCaretRect()) {
- if (!isNonOrphanedCaret(m_selection))
- clearCaretRect();
- else if (isTextFormControl(m_selection))
- m_absCaretBoundsDirty |= updateCaretRect(m_frame->document(), PositionWithAffinity(m_selection.start().isCandidate() ? m_selection.start() : Position(), m_selection.affinity()));
+ ASSERT(m_frame->document()->lifecycle().state() != DocumentLifecycle::InPaintInvalidation);
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+ if (!isNonOrphanedCaret(m_selection)) {
+ clearCaretRect();
+ } else {
+ if (isTextFormControl(m_selection))
+ updateCaretRect(m_frame->document(), PositionWithAffinity(m_selection.start().isCandidate() ? m_selection.start() : Position(), m_selection.affinity()));
else
- m_absCaretBoundsDirty |= updateCaretRect(m_frame->document(), VisiblePosition(m_selection.start(), m_selection.affinity()));
+ updateCaretRect(m_frame->document(), VisiblePosition(m_selection.start(), m_selection.affinity()));
}
-
- return localCaretRectWithoutUpdate();
+ return absoluteBoundsForLocalRect(m_selection.start().deprecatedNode(), localCaretRectWithoutUpdate());
}
-IntRect FrameSelection::absoluteCaretBounds()
+static LayoutRect localCaretRect(const VisibleSelection& m_selection, const PositionWithAffinity& caretPosition, RenderObject*& renderer)
{
- recomputeCaretRect();
- return m_absCaretBounds;
+ renderer = nullptr;
+ if (!isNonOrphanedCaret(m_selection))
+ return LayoutRect();
+
+ return localCaretRectOfPosition(caretPosition, renderer);
}
-bool FrameSelection::recomputeCaretRect()
+static void invalidateLocalCaretRect(RenderObject* renderer, const LayoutRect& caretRect)
{
- if (!shouldUpdateCaretRect())
- return false;
-
- if (!m_frame || !m_frame->document()->view())
- return false;
-
- LayoutRect oldRect = localCaretRectWithoutUpdate();
- LayoutRect newRect = localCaretRect();
- if (oldRect == newRect && !m_absCaretBoundsDirty)
- return false;
-
- IntRect oldAbsCaretBounds = m_absCaretBounds;
- m_absCaretBounds = absoluteBoundsForLocalRect(m_selection.start().deprecatedNode(), localCaretRectWithoutUpdate());
- m_absCaretBoundsDirty = false;
-
- if (oldAbsCaretBounds == m_absCaretBounds)
- return false;
-
- if (RenderView* view = m_frame->document()->renderView()) {
- if (m_previousCaretNode && shouldRepaintCaret(view, m_previousCaretNode->isContentEditable()))
- repaintCaretForLocalRect(m_previousCaretNode.get(), oldRect);
- Node* node = m_selection.start().deprecatedNode();
- m_previousCaretNode = node;
- if (shouldRepaintCaret(view, isContentEditable()))
- repaintCaretForLocalRect(node, newRect);
- }
-
- return true;
+ // FIXME: Need to over-paint 1 pixel to workaround some rounding problems.
+ // https://bugs.webkit.org/show_bug.cgi?id=108283
+ LayoutRect inflatedRect = caretRect;
+ inflatedRect.inflate(1);
+ renderer->invalidatePaintRectangle(inflatedRect);
}
void FrameSelection::invalidateCaretRect()
{
- if (!isCaret())
+ if (!m_caretRectDirty)
return;
+ m_caretRectDirty = false;
+
+ RenderObject* renderer = nullptr;
+ LayoutRect newRect = localCaretRect(m_selection, PositionWithAffinity(m_selection.start(), m_selection.affinity()), renderer);
+ Node* newNode = renderer ? renderer->node() : nullptr;
- CaretBase::invalidateCaretRect(m_selection.start().deprecatedNode(), recomputeCaretRect());
+ if (!m_caretBlinkTimer.isActive() && newNode == m_previousCaretNode && newRect == m_previousCaretRect)
+ return;
+
+ RenderView* view = m_frame->document()->renderView();
+ if (m_previousCaretNode && shouldRepaintCaret(view, m_previousCaretNode->isContentEditable()))
+ invalidateLocalCaretRect(m_previousCaretNode->renderer(), m_previousCaretRect);
+ if (newNode && shouldRepaintCaret(view, newNode->isContentEditable()))
+ invalidateLocalCaretRect(newNode->renderer(), newRect);
+
+ m_previousCaretNode = newNode;
+ m_previousCaretRect = newRect;
}
void FrameSelection::paintCaret(GraphicsContext* context, const LayoutPoint& paintOffset, const LayoutRect& clipRect)
{
- if (m_selection.isCaret() && m_caretPaint)
+ if (m_selection.isCaret() && m_caretPaint) {
+ updateCaretRect(m_frame->document(), m_selection.visibleStart());
CaretBase::paintCaret(m_selection.start().deprecatedNode(), context, paintOffset, clipRect);
+ }
}
bool FrameSelection::contains(const LayoutPoint& point)
@@ -1465,8 +1461,7 @@ void FrameSelection::notifyCompositorForSelectionChange()
if (!RuntimeEnabledFeatures::compositedSelectionUpdatesEnabled())
return;
- if (Page* page = m_frame->page())
- page->animator().scheduleVisualUpdate();
+ scheduleVisualUpdate();
}
void FrameSelection::focusedOrActiveStateChanged()
@@ -1540,23 +1535,23 @@ inline static bool shouldStopBlinkingDueToTypingCommand(LocalFrame* frame)
return frame->editor().lastEditCommand() && frame->editor().lastEditCommand()->shouldStopCaretBlinking();
}
-void FrameSelection::updateAppearance()
+void FrameSelection::updateAppearance(ResetCaretBlinkOption option)
{
// Paint a block cursor instead of a caret in overtype mode unless the caret is at the end of a line (in this case
// the FrameSelection will paint a blinking caret as usual).
bool paintBlockCursor = m_shouldShowBlockCursor && m_selection.isCaret() && !isLogicalEndOfLine(m_selection.visibleEnd());
- bool caretRectChangedOrCleared = recomputeCaretRect();
bool shouldBlink = !paintBlockCursor && shouldBlinkCaret();
+ bool willNeedCaretRectUpdate = false;
+
// If the caret moved, stop the blink timer so we can restart with a
// black caret in the new location.
- if (caretRectChangedOrCleared || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame)) {
+ if (option == ResetCaretBlink || !shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame)) {
m_caretBlinkTimer.stop();
- if (!shouldBlink && m_caretPaint) {
- m_caretPaint = false;
- invalidateCaretRect();
- }
+
+ m_caretPaint = false;
+ willNeedCaretRectUpdate = true;
}
// Start blinking with a black caret. Be sure not to restart if we're
@@ -1565,20 +1560,28 @@ void FrameSelection::updateAppearance()
if (double blinkInterval = RenderTheme::theme().caretBlinkInterval())
m_caretBlinkTimer.startRepeating(blinkInterval, FROM_HERE);
- if (!m_caretPaint) {
- m_caretPaint = true;
- invalidateCaretRect();
- }
+ m_caretPaint = true;
+ willNeedCaretRectUpdate = true;
}
+ if (willNeedCaretRectUpdate)
+ setCaretRectNeedsUpdate();
+
RenderView* view = m_frame->contentRenderer();
if (!view)
return;
// Construct a new VisibleSolution, since m_selection is not necessarily valid, and the following steps
// assume a valid selection. See <https://bugs.webkit.org/show_bug.cgi?id=69563> and <rdar://problem/10232866>.
- VisiblePosition endVisiblePosition = paintBlockCursor ? modifyExtendingForward(CharacterGranularity) : m_selection.visibleEnd();
- VisibleSelection selection(m_selection.visibleStart(), endVisiblePosition);
+
+ VisibleSelection selection;
+ if (isTextFormControl(m_selection)) {
+ Position endPosition = paintBlockCursor ? m_selection.extent().next() : m_selection.end();
+ selection.setWithoutValidation(m_selection.start(), endPosition);
+ } else {
+ VisiblePosition endVisiblePosition = paintBlockCursor ? modifyExtendingForward(CharacterGranularity) : m_selection.visibleEnd();
+ selection = VisibleSelection(m_selection.visibleStart(), endVisiblePosition);
+ }
if (!selection.isRange()) {
view->clearSelection();
@@ -1613,11 +1616,6 @@ void FrameSelection::setCaretVisibility(CaretVisibility visibility)
if (caretVisibility() == visibility)
return;
- m_frame->document()->updateLayoutIgnorePendingStylesheets();
- if (m_caretPaint) {
- m_caretPaint = false;
- invalidateCaretRect();
- }
CaretBase::setCaretVisibility(visibility);
updateAppearance();
@@ -1649,13 +1647,11 @@ void FrameSelection::caretBlinkTimerFired(Timer<FrameSelection>*)
if (isCaretBlinkingSuspended() && m_caretPaint)
return;
m_caretPaint = !m_caretPaint;
- invalidateCaretRect();
+ setCaretRectNeedsUpdate();
}
void FrameSelection::notifyRendererOfSelectionChange(EUserTriggered userTriggered)
{
- m_frame->document()->updateRenderTreeIfNeeded();
-
if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(start()))
textControl->selectionChanged(userTriggered == UserTriggered);
}
@@ -1915,6 +1911,21 @@ void FrameSelection::trace(Visitor* visitor)
VisibleSelection::ChangeObserver::trace(visitor);
}
+void FrameSelection::setCaretRectNeedsUpdate()
+{
+ m_caretRectDirty = true;
+
+ scheduleVisualUpdate();
+}
+
+void FrameSelection::scheduleVisualUpdate() const
+{
+ if (!m_frame)
+ return;
+ if (Page* page = m_frame->page())
+ page->animator().scheduleVisualUpdate();
+}
+
}
#ifndef NDEBUG
« no previous file with comments | « Source/core/editing/FrameSelection.h ('k') | Source/core/frame/FrameView.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698