⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 273621 in webkit


Ignore:
Timestamp:
Feb 27, 2021, 12:24:02 AM (6 years ago)
Author:
Antti Koivisto
Message:

Render tree updates for Text node content mutations should happen during rendering update
​https://bugs.webkit.org/show_bug.cgi?id=222406

Reviewed by Simon Fraser.

Source/WebCore:

Calls to Text.insertData and similar should not mutate render tree synchronously.
Instead render tree should be updated during the next rendering update along with
any style changes.

These updates already go via RenderTreeUpdater. We just need to save the information
about which nodes need updating so the next rendering update can pick them up.

This seems to help with some performance benchmarks.

  • dom/CharacterData.cpp:

(WebCore::CharacterData::parserAppendData):
(WebCore::CharacterData::setDataAndUpdate):

Move in-tree check to the updateRendererAfterContentChange and make it use isConnected().

  • dom/Document.cpp:

(WebCore::Document::removedLastRef):
(WebCore::Document::resolveStyle):

Include the text update when updating the render tree.

(WebCore::Document::updateTextRenderer):

Create a text update that will get flushed during the next rendering update.

(WebCore::Document::needsStyleRecalc const):

We need to recalc if there are pending text updates.

  • dom/Document.h:
  • dom/Text.cpp:

(WebCore::Text::splitText):

Use updateRendererAfterContentChange instead of poking render tree directly.

(WebCore::Text::updateRendererAfterContentChange):

  • rendering/updating/RenderTreeUpdater.cpp:
  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::TreeResolver):
(WebCore::Style::TreeResolver::resolve):

  • style/StyleTreeResolver.h:

(WebCore::Style::TreeResolver::TreeResolver):

  • style/StyleUpdate.cpp:

(WebCore::Style::Update::addText):

Merge text updates.

(WebCore::Style::Update::addPossibleRoot):

  • style/StyleUpdate.h:

(WebCore::Style::Update::roots const):
(WebCore::Style::Update:: const): Deleted.

Refcount the nodes since this now has longer lifetime.

  • editing/CompositeEditCommand.cpp:

(WebCore::CompositeEditCommand::deleteInsignificantText):

Ensure we leave deleteInsignificantText with updated render tree. Clients expect that.
Do layout (instead of just style update) for consistency, deleteInsignificantText does one anyway in beginning.

  • editing/markup.cpp:

(WebCore::replaceChildrenWithFragment):

Pending text update may ref the node so this refcount assert is not correct.

  • style/StyleUpdate.cpp:

(WebCore::Style::Update::addText):

LayoutTests:

These are progressions.

  • fast/text/splitText-dirty-lines-expected.txt:
  • imported/blink/fast/css/first-letter-range-insert-expected.txt:

Here we were actually drawing text that didn't exist in DOM anymore.

Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r273616 r273621  
     12021-02-27  Antti Koivisto  <antti@apple.com>
     2
     3        Render tree updates for Text node content mutations should happen during rendering update
     4        https://bugs.webkit.org/show_bug.cgi?id=222406
     5
     6        Reviewed by Simon Fraser.
     7
     8        These are progressions.
     9
     10        * fast/text/splitText-dirty-lines-expected.txt:
     11        * imported/blink/fast/css/first-letter-range-insert-expected.txt:
     12
     13        Here we were actually drawing text that didn't exist in DOM anymore.
     14
    1152021-02-26  Peng Liu  <peng.liu6@apple.com>
    216
  • trunk/LayoutTests/fast/text/splitText-dirty-lines-expected.txt

    r62134 r273621  
    1616layer at (8,8) size 200x160
    1717  RenderBlock (positioned) {DIV} at (0,0) size 200x160 [color=#008000]
    18     RenderText {#text} at (0,0) size 0x0
    1918    RenderText {#text} at (0,0) size 160x160
    2019      text run at (0,0) width 160: "AAAA"
  • trunk/LayoutTests/fast/text/text-combine-surroundContents-crash-expected.txt

    r235615 r273621  
    11layer at (0,0) size 800x600
    22  RenderView at (0,0) size 800x600
    3 layer at (0,0) size 800x76
    4   RenderBlock {HTML} at (0,0) size 800x76
    5     RenderBody {BODY} at (8,8) size 784x60
    6       RenderBlock {DIV} at (0,0) size 20x40
    7         RenderCombineText {#text} at (0,0) size 0x0
    8         RenderInline {SPAN} at (0,0) size 20x0
    9         RenderCombineText {#text} at (0,20) size 20x20
    10           text run at (0,20) width 20: "\x{FFFC}"
    11       RenderBlock (anonymous) at (0,40) size 784x0
     3layer at (0,0) size 800x56
     4  RenderBlock {HTML} at (0,0) size 800x56
     5    RenderBody {BODY} at (8,8) size 784x40
     6      RenderBlock {DIV} at (0,0) size 20x20
     7        RenderInline {SPAN} at (0,0) size 0x0
     8        RenderCombineText {#text} at (0,0) size 20x20
     9          text run at (0,0) width 20: "\x{FFFC}"
     10      RenderBlock (anonymous) at (0,20) size 784x0
    1211        RenderText {#text} at (0,0) size 0x0
    1312        RenderText {#text} at (0,0) size 0x0
    14       RenderBlock {DIV} at (0,40) size 784x20
     13      RenderBlock {DIV} at (0,20) size 784x20
    1514        RenderText {#text} at (0,0) size 400x20
    1615          text run at (0,0) width 400: "PASS, did not crash."
  • trunk/LayoutTests/imported/blink/fast/css/first-letter-range-insert-expected.txt

    r220646 r273621  
    1 B
    21
  • trunk/Source/WebCore/ChangeLog

    r273620 r273621  
     12021-02-27  Antti Koivisto  <antti@apple.com>
     2
     3        Render tree updates for Text node content mutations should happen during rendering update
     4        https://bugs.webkit.org/show_bug.cgi?id=222406
     5
     6        Reviewed by Simon Fraser.
     7
     8        Calls to Text.insertData and similar should not mutate render tree synchronously.
     9        Instead render tree should be updated during the next rendering update along with
     10        any style changes.
     11
     12        These updates already go via RenderTreeUpdater. We just need to save the information
     13        about which nodes need updating so the next rendering update can pick them up.
     14
     15        This seems to help with some performance benchmarks.
     16
     17        * dom/CharacterData.cpp:
     18        (WebCore::CharacterData::parserAppendData):
     19        (WebCore::CharacterData::setDataAndUpdate):
     20
     21        Move in-tree check to the updateRendererAfterContentChange and make it use isConnected().
     22
     23        * dom/Document.cpp:
     24        (WebCore::Document::removedLastRef):
     25        (WebCore::Document::resolveStyle):
     26
     27        Include the text update when updating the render tree.
     28
     29        (WebCore::Document::updateTextRenderer):
     30
     31        Create a text update that will get flushed during the next rendering update.
     32
     33        (WebCore::Document::needsStyleRecalc const):
     34
     35        We need to recalc if there are pending text updates.
     36
     37        * dom/Document.h:
     38        * dom/Text.cpp:
     39        (WebCore::Text::splitText):
     40
     41        Use updateRendererAfterContentChange instead of poking render tree directly.
     42
     43        (WebCore::Text::updateRendererAfterContentChange):
     44        * rendering/updating/RenderTreeUpdater.cpp:
     45        * style/StyleTreeResolver.cpp:
     46        (WebCore::Style::TreeResolver::TreeResolver):
     47        (WebCore::Style::TreeResolver::resolve):
     48        * style/StyleTreeResolver.h:
     49        (WebCore::Style::TreeResolver::TreeResolver):
     50        * style/StyleUpdate.cpp:
     51        (WebCore::Style::Update::addText):
     52
     53        Merge text updates.
     54
     55        (WebCore::Style::Update::addPossibleRoot):
     56        * style/StyleUpdate.h:
     57        (WebCore::Style::Update::roots const):
     58        (WebCore::Style::Update:: const): Deleted.
     59
     60        Refcount the nodes since this now has longer lifetime.
     61
     62        * editing/CompositeEditCommand.cpp:
     63        (WebCore::CompositeEditCommand::deleteInsignificantText):
     64
     65        Ensure we leave deleteInsignificantText with updated render tree. Clients expect that.
     66        Do layout (instead of just style update) for consistency, deleteInsignificantText does one anyway in beginning.
     67
     68        * editing/markup.cpp:
     69        (WebCore::replaceChildrenWithFragment):
     70
     71        Pending text update may ref the node so this refcount assert is not correct.
     72
     73        * style/StyleUpdate.cpp:
     74        (WebCore::Style::Update::addText):
     75
    1762021-02-27  Megan Gardner  <megan_gardner@apple.com>
    277
  • trunk/Source/WebCore/dom/CharacterData.cpp

    r269161 r273621  
    103103
    104104    ASSERT(!renderer() || is<Text>(*this));
    105     if (is<Text>(*this) && parentNode())
     105    if (is<Text>(*this))
    106106        downcast<Text>(*this).updateRendererAfterContentChange(oldLength, 0);
    107107
    … …  
    183183
    184184    ASSERT(!renderer() || is<Text>(*this));
    185     if (is<Text>(*this) && parentNode())
     185    if (is<Text>(*this))
    186186        downcast<Text>(*this).updateRendererAfterContentChange(offsetOfReplacedData, oldLength);
    187187
  • trunk/Source/WebCore/dom/Document.cpp

    r273415 r273621  
    808808#endif
    809809        m_associatedFormControls.clear();
     810        m_pendingRenderTreeTextUpdate = { };
    810811
    811812        m_fontSelector->stopLoadingAndClearFonts();
    … …  
    20532054        }
    20542055
    2055         Style::TreeResolver resolver(*this);
     2056        Style::TreeResolver resolver(*this, WTFMove(m_pendingRenderTreeTextUpdate));
    20562057        auto styleUpdate = resolver.resolve();
    20572058
    … …  
    21012102void Document::updateTextRenderer(Text& text, unsigned offsetOfReplacedText, unsigned lengthOfReplacedText)
    21022103{
    2103     auto textUpdate = makeUnique<Style::Update>(*this);
    2104     textUpdate->addText(text, { offsetOfReplacedText, lengthOfReplacedText, WTF::nullopt });
    2105 
    2106     updateRenderTree(WTFMove(textUpdate));
     2104    if (!m_pendingRenderTreeTextUpdate)
     2105        m_pendingRenderTreeTextUpdate = makeUnique<Style::Update>(*this);
     2106
     2107    m_pendingRenderTreeTextUpdate->addText(text, { offsetOfReplacedText, lengthOfReplacedText, WTF::nullopt });
     2108
     2109    scheduleRenderingUpdate({ });
    21072110}
    21082111
    … …  
    21162119
    21172120    if (childNeedsStyleRecalc())
     2121        return true;
     2122
     2123    if (m_pendingRenderTreeTextUpdate)
    21182124        return true;
    21192125
  • trunk/Source/WebCore/dom/Document.h

    r272707 r273621  
    18041804    Timer m_styleRecalcTimer;
    18051805
     1806    std::unique_ptr<Style::Update> m_pendingRenderTreeTextUpdate;
     1807
    18061808    Element* m_cssTarget { nullptr };
    18071809
  • trunk/Source/WebCore/dom/Text.cpp

    r267220 r273621  
    7777    document().textNodeSplit(*this);
    7878
    79     if (renderer())
    80         renderer()->setTextWithOffset(data(), 0, oldData.length());
     79    updateRendererAfterContentChange(0, oldData.length());
    8180
    8281    return newText;
    … …  
    216215void Text::updateRendererAfterContentChange(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
    217216{
    218     ASSERT(parentNode());
     217    if (!isConnected())
     218        return;
     219
    219220    if (styleValidity() >= Style::Validity::SubtreeAndRenderersInvalid)
    220221        return;
  • trunk/Source/WebCore/editing/CompositeEditCommand.cpp

    r273468 r273621  
    10591059        deleteInsignificantText(textNode, startOffset, endOffset);
    10601060    }
     1061    if (!nodes.isEmpty()) {
     1062        // Callers expect render tree to be in sync.
     1063        document().updateLayoutIgnorePendingStylesheets();
     1064    }
    10611065}
    10621066
  • trunk/Source/WebCore/editing/markup.cpp

    r273375 r273621  
    13861386    if (containerChild && !containerChild->nextSibling()) {
    13871387        if (is<Text>(*containerChild) && hasOneTextChild(fragment) && canUseSetDataOptimization(downcast<Text>(*containerChild), mutation)) {
    1388             ASSERT(!fragment->firstChild()->refCount());
    13891388            downcast<Text>(*containerChild).setData(downcast<Text>(*fragment->firstChild()).data());
    13901389            return { };
  • trunk/Source/WebCore/rendering/updating/RenderTreeUpdater.cpp

    r269813 r273621  
    103103{
    104104    ListHashSet<ContainerNode*> renderingRoots;
    105     for (auto* root : update.roots()) {
     105    for (auto& root : update.roots()) {
    106106        auto* renderingRoot = findRenderingRoot(*root);
    107107        if (!renderingRoot)
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r273003 r273621  
    6363DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(TreeResolverScope);
    6464
    65 TreeResolver::TreeResolver(Document& document)
     65TreeResolver::TreeResolver(Document& document, std::unique_ptr<Update> update)
    6666    : m_document(document)
     67    , m_update(WTFMove(update))
    6768{
    6869}
    … …  
    577578    }
    578579    if (!documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
    579         return nullptr;
     580        return WTFMove(m_update);
    580581
    581582    m_didSeePendingStylesheet = m_document.styleScope().hasPendingSheetsBeforeBody();
    582583
    583     m_update = makeUnique<Update>(m_document);
     584    if (!m_update)
     585        m_update = makeUnique<Update>(m_document);
    584586    m_scopeStack.append(adoptRef(*new Scope(m_document)));
    585587    m_parentStack.append(Parent(m_document));
  • trunk/Source/WebCore/style/StyleTreeResolver.h

    r270837 r273621  
    5050class TreeResolver {
    5151public:
    52     TreeResolver(Document&);
     52    TreeResolver(Document&, std::unique_ptr<Update> = { });
    5353    ~TreeResolver();
    5454
  • trunk/Source/WebCore/style/StyleUpdate.cpp

    r223604 r273621  
    9797void Update::addText(Text& text, Element* parent, TextUpdate&& textUpdate)
    9898{
    99     ASSERT(!m_texts.contains(&text));
    10099    ASSERT(composedTreeAncestors(text).first() == parent);
    101100
    102101    addPossibleRoot(parent);
    103     m_texts.add(&text, WTFMove(textUpdate));
     102    auto result = m_texts.ensure(&text, [&] {
     103        return WTFMove(textUpdate);
     104    });
     105    if (!result.isNewEntry) {
     106        auto& entry = result.iterator->value;
     107        auto startOffset = std::min(entry.offset, textUpdate.offset);
     108        auto endOffset = std::max(entry.offset + entry.length, textUpdate.offset + textUpdate.length);
     109        entry.offset = startOffset;
     110        entry.length = endOffset - startOffset;
     111       
     112        ASSERT(!entry.inheritedDisplayContentsStyle || !textUpdate.inheritedDisplayContentsStyle);
     113        if (!entry.inheritedDisplayContentsStyle)
     114            entry.inheritedDisplayContentsStyle = WTFMove(textUpdate.inheritedDisplayContentsStyle);
     115    }
    104116}
    105117
    … …  
    112124{
    113125    if (!element) {
    114         m_roots.add(&m_document);
     126        m_roots.add(m_document.ptr());
    115127        return;
    116128    }
  • trunk/Source/WebCore/style/StyleUpdate.h

    r269813 r273621  
    7070    Update(Document&);
    7171
    72     const ListHashSet<ContainerNode*>& roots() const { return m_roots; }
     72    const ListHashSet<RefPtr<ContainerNode>>& roots() const { return m_roots; }
    7373
    7474    const ElementUpdates* elementUpdates(const Element&) const;
    … …  
    9191    void addPossibleRoot(Element*);
    9292
    93     Document& m_document;
    94     ListHashSet<ContainerNode*> m_roots;
    95     HashMap<const Element*, ElementUpdates> m_elements;
    96     HashMap<const Text*, TextUpdate> m_texts;
     93    Ref<Document> m_document;
     94    ListHashSet<RefPtr<ContainerNode>> m_roots;
     95    HashMap<RefPtr<const Element>, ElementUpdates> m_elements;
     96    HashMap<RefPtr<const Text>, TextUpdate> m_texts;
    9797};
    9898
Note: See TracChangeset for help on using the changeset viewer.