Changeset 164133 in webkit


Ignore:
Timestamp:
Feb 14, 2014 2:27:04 PM (10 years ago)
Author:
rniwa@webkit.org
Message:

setSelection should not synchronously trigger layout
https://bugs.webkit.org/show_bug.cgi?id=128797

Reviewed by Antti Koivisto.

Only update the appearance and reveal selection when the style and the layout is already up to date.
Otherwise, do so in performPostLayoutTasks.

  • editing/FrameSelection.cpp:

(WebCore::FrameSelection::FrameSelection):
(WebCore::FrameSelection::setSelection): Set m_pendingSelectionUpdate and synchronously update caret rect
if we don't need to update style or layout.
(WebCore::updateSelectionByUpdatingLayoutOrStyle): Added. Used by FrameSelection member functions to
trigger layout or style recalc whichever is needed.
(WebCore::FrameSelection::updateAndRevealSelection): Extracted from setSelection.
(WebCore::FrameSelection::absoluteCaretBounds): Call updateSelectionByUpdatingLayoutOrStyle since caret rect
is no longer updated synchronously in setSelection.
(WebCore::FrameSelection::recomputeCaretRect): Don't assert that visibleStart().absoluteCaretBounds() is
equal to m_absCaretBounds since selection may no longer be caret at this point.
(WebCore::FrameSelection::setCaretVisibility): Call updateSelectionByUpdatingLayoutOrStyle since we're
synchronously calling into updateAppearance here. In the future, we should make this asynchronous as well.
(WebCore::FrameSelection::selectionBounds): Call updateSelectionByUpdatingLayoutOrStyle since selection bounds
could be outdated. This code only triggering style recalc was presumably a bug.

  • editing/FrameSelection.h:
  • page/FrameView.cpp:

(WebCore::FrameView::performPostLayoutTasks): Update selection's appearance and scroll to reveal selection
as needed.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r164131 r164133  
     12014-02-13  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        setSelection should not synchronously trigger layout
     4        https://bugs.webkit.org/show_bug.cgi?id=128797
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Only update the appearance and reveal selection when the style and the layout is already up to date.
     9        Otherwise, do so in performPostLayoutTasks.
     10
     11        * editing/FrameSelection.cpp:
     12        (WebCore::FrameSelection::FrameSelection):
     13        (WebCore::FrameSelection::setSelection): Set m_pendingSelectionUpdate and synchronously update caret rect
     14        if we don't need to update style or layout.
     15        (WebCore::updateSelectionByUpdatingLayoutOrStyle): Added. Used by FrameSelection member functions to
     16        trigger layout or style recalc whichever is needed.
     17        (WebCore::FrameSelection::updateAndRevealSelection): Extracted from setSelection.
     18        (WebCore::FrameSelection::absoluteCaretBounds): Call updateSelectionByUpdatingLayoutOrStyle since caret rect
     19        is no longer updated synchronously in setSelection.
     20        (WebCore::FrameSelection::recomputeCaretRect): Don't assert that visibleStart().absoluteCaretBounds() is
     21        equal to m_absCaretBounds since selection may no longer be caret at this point.
     22        (WebCore::FrameSelection::setCaretVisibility): Call updateSelectionByUpdatingLayoutOrStyle since we're
     23        synchronously calling into updateAppearance here. In the future, we should make this asynchronous as well.
     24        (WebCore::FrameSelection::selectionBounds): Call updateSelectionByUpdatingLayoutOrStyle since selection bounds
     25        could be outdated. This code only triggering style recalc was presumably a bug.
     26        * editing/FrameSelection.h:
     27
     28        * page/FrameView.cpp:
     29        (WebCore::FrameView::performPostLayoutTasks): Update selection's appearance and scroll to reveal selection
     30        as needed.
     31
    1322014-02-14  Andreas Kling  <akling@apple.com>
    233
  • trunk/Source/WebCore/editing/FrameSelection.cpp

    r163920 r164133  
    117117    , m_focused(frame && frame->page() && frame->page()->focusController().focusedFrame() == frame)
    118118    , m_shouldShowBlockCursor(false)
     119    , m_pendingSelectionUpdate(false)
     120    , m_shouldRevealSelection(false)
     121    , m_alwaysAlignCursorOnScrollWhenRevealingSelection(false)
    119122#if PLATFORM(IOS)
    120123    , m_updateAppearanceEnabled(false)
     
    314317        return;
    315318
     319    Document* document = m_frame->document();
     320    if (!document)
     321        return;
     322
     323    m_shouldRevealSelection = options & RevealSelection;
     324    m_alwaysAlignCursorOnScrollWhenRevealingSelection = align == AlignCursorOnScrollAlways;
     325
     326    m_pendingSelectionUpdate = true;
     327
     328    if (document->hasPendingStyleRecalc())
     329        return;
     330
     331    FrameView* frameView = document->view();
     332    if (frameView && frameView->layoutPending())
     333        return;
     334
     335    updateAndRevealSelection();
     336}
     337
     338static void updateSelectionByUpdatingLayoutOrStyle(Frame& frame)
     339{
    316340#if ENABLE(TEXT_CARET)
    317     m_frame->document()->updateLayoutIgnorePendingStylesheets();
     341    frame.document()->updateLayoutIgnorePendingStylesheets();
    318342#else
    319     m_frame->document()->updateStyleIfNeeded();
    320 #endif
     343    frame.document()->updateStyleIfNeeded();
     344#endif
     345}
     346
     347void FrameSelection::updateAndRevealSelection()
     348{
     349    if (!m_pendingSelectionUpdate)
     350        return;
     351
     352    m_pendingSelectionUpdate = false;
     353
    321354    updateAppearance();
    322355
    323     if (options & RevealSelection) {
     356    if (m_shouldRevealSelection) {
    324357        ScrollAlignment alignment;
    325358
    326359        if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed())
    327             alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
     360            alignment = m_alwaysAlignCursorOnScrollWhenRevealingSelection ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
    328361        else
    329             alignment = (align == AlignCursorOnScrollAlways) ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
     362            alignment = m_alwaysAlignCursorOnScrollWhenRevealingSelection ? ScrollAlignment::alignTopAlways : ScrollAlignment::alignToEdgeIfNeeded;
    330363
    331364        revealSelection(alignment, RevealExtent);
     
    13091342IntRect FrameSelection::absoluteCaretBounds()
    13101343{
     1344    if (!m_frame)
     1345        return IntRect();
     1346    updateSelectionByUpdatingLayoutOrStyle(*m_frame);
    13111347    recomputeCaretRect();
    13121348    return m_absCaretBounds;
     
    13561392    m_absCaretBounds = absoluteBoundsForLocalCaretRect(rendererForCaretPainting(caretNode.get()), newRect);
    13571393
    1358     if (m_absCaretBoundsDirty) // We should be able to always assert this condition.
     1394    if (m_absCaretBoundsDirty && m_selection.isCaret()) // We should be able to always assert this condition.
    13591395        ASSERT(m_absCaretBounds == m_selection.visibleStart().absoluteCaretBounds());
    13601396
     
    18151851        return;
    18161852
     1853    // FIXME: We shouldn't trigger a synchrnously layout here.
     1854    if (m_frame)
     1855        updateSelectionByUpdatingLayoutOrStyle(*m_frame);
     1856
    18171857#if ENABLE(TEXT_CARET)
    1818     m_frame->document()->updateLayoutIgnorePendingStylesheets();
    18191858    if (m_caretPaint) {
    18201859        m_caretPaint = false;
     
    18221861    }
    18231862    CaretBase::setCaretVisibility(visibility);
    1824 #else
    1825     m_frame->document()->updateStyleIfNeeded();
    18261863#endif
    18271864
     
    19211958        return LayoutRect();
    19221959
    1923     m_frame->document()->updateStyleIfNeeded();
     1960    updateSelectionByUpdatingLayoutOrStyle(*m_frame);
    19241961    RenderView* root = m_frame->contentRenderer();
    19251962    FrameView* view = m_frame->view();
  • trunk/Source/WebCore/editing/FrameSelection.h

    r163920 r164133  
    144144    const VisibleSelection& selection() const { return m_selection; }
    145145    void setSelection(const VisibleSelection&, SetSelectionOptions = defaultSetSelectionOptions(), CursorAlignOnScroll = AlignCursorOnScrollIfNeeded, TextGranularity = CharacterGranularity);
     146    void updateAndRevealSelection();
    146147    bool setSelectedRange(Range*, EAffinity, bool closeTyping);
    147148    void selectAll();
     
    332333    bool m_focused : 1;
    333334    bool m_shouldShowBlockCursor : 1;
     335    bool m_pendingSelectionUpdate : 1;
     336    bool m_shouldRevealSelection : 1;
     337    bool m_alwaysAlignCursorOnScrollWhenRevealingSelection : 1;
    334338
    335339#if PLATFORM(IOS)
  • trunk/Source/WebCore/page/FrameView.cpp

    r163973 r164133  
    26282628
    26292629    frame().selection().setCaretRectNeedsUpdate();
    2630     frame().selection().updateAppearance();
     2630    frame().selection().updateAndRevealSelection();
    26312631
    26322632    LayoutMilestones requestedMilestones = 0;
Note: See TracChangeset for help on using the changeset viewer.