Separate render tree updating from style resolve
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Apr 2016 09:54:12 +0000 (09:54 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Apr 2016 09:54:12 +0000 (09:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155298

Reviewed by Andreas Kling.

Source/WebCore:

This patch splits computing document style and applying the results into two distinct steps:

Style::TreeResolver::resolve()
        |
        | Style::Update
        V
RenderTreeUpdater::commit()

Style::TreeResolver::resolve() returns a Style::Update object that contains all the changes to be made
for the whole composed tree. RenderTreeUpdater then applies the changes updating, building or tearing
down portions of the render tree as needed.

Style::Update consists of a map that contains new style for each newly resolved element along with some
metadata. A separate map contains text nodes that require reconstruction. It also tracks change roots so
RenderTreeUpdater needs to traverse the changed subtrees only.

The patch eliminates the recursive render tree build code path replacing it with iterative functions.

This will enable future optimizations. For example we won't need to commit to immediate rendering
changes simply because some script or internal function requires up-to-date style.

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::State::State):
(WebCore::StyleResolver::styleForElement):
* css/StyleResolver.h:
(WebCore::StyleResolver::setOverrideDocumentElementStyle):
(WebCore::StyleResolver::State::State):

    Root element style is needed for resolving other elements. Add a way to provide it without looking
    into active document style.

* dom/Document.cpp:
(WebCore::Document::recalcStyle):

    Resolve the document style and commit it immediately (for now).

(WebCore::Document::styleForElementIgnoringPendingStylesheets):
* dom/Document.h:
(WebCore::Document::setNeedsNotifyRemoveAllPendingStylesheet):
(WebCore::Document::inStyleRecalc):
(WebCore::Document::inRenderTreeUpdate):
* dom/Element.cpp:
(WebCore::Element::setChildIndex):

    Setting the unique bit is now done by style relations update code.

* dom/Node.cpp:
(WebCore::Node::setNeedsStyleRecalc):

    Prevent spurious style invalidation during render tree updating.

* rendering/RenderBox.cpp:
(WebCore::RenderBox::styleDidChange):

    Capturing body element color for color:-webkit-text is now done by TreeResolver.

* rendering/RenderElement.h:
(WebCore::RenderElement::setAnimatableStyle): Deleted.

    No longer used.

* style/RenderTreePosition.cpp:
(WebCore::RenderTreePosition::nextSiblingRenderer):

    Skip over non-rendered slot elements.

* style/RenderTreeUpdater.cpp: Added.
(WebCore::RenderTreeUpdater::Parent::Parent):
(WebCore::RenderTreeUpdater::RenderTreeUpdater):
(WebCore::hasDisplayContents):
(WebCore::findRenderingRoot):
(WebCore::RenderTreeUpdater::commit):

    Call updateRenderTree for each change root.

(WebCore::shouldCreateRenderer):
(WebCore::RenderTreeUpdater::updateRenderTree):

    Iteratively traverse the composed tree starting for a change root.
    Apply the changes calling updateElementRenderer and updateTextRenderer as needed.
    Enter subtrees that haves changes to apply.

(WebCore::RenderTreeUpdater::renderTreePosition):

    We may not create renderers for all elements (<slot> or more generally display:contents) that
    have rendered descendants. Search the parent stack to find the valid position.

(WebCore::RenderTreeUpdater::pushParent):
(WebCore::RenderTreeUpdater::popParent):
(WebCore::RenderTreeUpdater::popParentsToDepth):

    Maintain parent stack.

(WebCore::pseudoStyleCacheIsInvalid):
(WebCore::RenderTreeUpdater::updateElementRenderer):

    Create, delete or update the renderer.

(WebCore::moveToFlowThreadIfNeeded):
(WebCore::RenderTreeUpdater::createRenderer):
(WebCore::textRendererIsNeeded):
(WebCore::createTextRenderer):
(WebCore::RenderTreeUpdater::updateTextRenderer):
(WebCore::RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded):

    This is moved from TreeResolver.

(WebCore::needsPseudoElement):
(WebCore::RenderTreeUpdater::updateBeforeOrAfterPseudoElement):

    Pseudo elements are handled entirely during render tree construction. Compute their style and
    create or delete them as needed.

* style/RenderTreeUpdater.h: Added.
(WebCore::RenderTreeUpdater::parent):
* style/StyleRelations.cpp:
(WebCore::Style::commitRelationsToRenderStyle):
(WebCore::Style::commitRelations):

    Commit to Style::Update instead of the document if needed.

(WebCore::Style::commitRelationsToDocument): Deleted.
* style/StyleRelations.h:
* style/StyleSharingResolver.cpp:
(WebCore::Style::elementHasDirectionAuto):
(WebCore::Style::SharingResolver::resolve):

    Fetch the shareable style from Style::Update instead of the active document style.

(WebCore::Style::SharingResolver::findSibling):
(WebCore::Style::SharingResolver::canShareStyleWithElement):
* style/StyleSharingResolver.h:
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::Parent::Parent):

    No need for render tree position anymore.

(WebCore::Style::TreeResolver::popScope):
(WebCore::Style::TreeResolver::styleForElement):
(WebCore::Style::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded):
(WebCore::Style::createTextRendererIfNeeded):
(WebCore::Style::updateTextRendererAfterContentChange):
(WebCore::Style::resetStyleForNonRenderedDescendants):
(WebCore::Style::detachChildren):
(WebCore::Style::detachSlotAssignees):
(WebCore::Style::detachRenderTree):
(WebCore::Style::TreeResolver::resolveElement):

    Just resolve the style and return it, no more applying or entering render tree construction code paths.

(WebCore::Style::resolveTextNode):
(WebCore::Style::elementImplicitVisibility):
(WebCore::Style::TreeResolver::pushParent):
(WebCore::Style::TreeResolver::popParent):
(WebCore::Style::TreeResolver::popParentsToDepth):
(WebCore::Style::shouldResolvePseudoElement):
(WebCore::Style::TreeResolver::resolveComposedTree):

    Add style changes to Style::Update.

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

    Return Style::Update object if non-empty.

(WebCore::Style::postResolutionCallbackQueue):
(WebCore::Style::shouldCreateRenderer): Deleted.
(WebCore::Style::moveToFlowThreadIfNeeded): Deleted.
(WebCore::Style::TreeResolver::createRenderer): Deleted.
(WebCore::Style::TreeResolver::createRenderTreeForChildren): Deleted.
(WebCore::Style::TreeResolver::createRenderTreeForShadowRoot): Deleted.
(WebCore::Style::beforeOrAfterPseudoElement): Deleted.
(WebCore::Style::setBeforeOrAfterPseudoElement): Deleted.
(WebCore::Style::clearBeforeOrAfterPseudoElement): Deleted.
(WebCore::Style::needsPseudoElement): Deleted.
(WebCore::Style::TreeResolver::createRenderTreeForBeforeOrAfterPseudoElement): Deleted.
(WebCore::Style::TreeResolver::createRenderTreeForSlotAssignees): Deleted.
(WebCore::Style::TreeResolver::createRenderTreeRecursively): Deleted.
(WebCore::Style::pseudoStyleCacheIsInvalid): Deleted.
(WebCore::Style::TreeResolver::resolveBeforeOrAfterPseudoElement): Deleted.

    Remove the recursive render tree building code path.

* style/StyleTreeResolver.h:
(WebCore::Style::TreeResolver::scope):
* style/StyleUpdate.cpp: Added.
(WebCore::Style::Update::Update):
(WebCore::Style::Update::elementUpdate):
(WebCore::Style::Update::textUpdate):
(WebCore::Style::Update::elementStyle):
(WebCore::Style::Update::addElement):
(WebCore::Style::Update::addText):
(WebCore::Style::Update::addPossibleRoot):
* style/StyleUpdate.h: Added.
(WebCore::Style::Update::roots):
(WebCore::Style::Update::document):
* svg/SVGElement.h:
(WebCore::SVGElement::updateRelativeLengthsInformation):
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::svgAttributeChanged):
(WebCore::SVGUseElement::willRecalcStyle):
(WebCore::SVGUseElement::willAttachRenderers): Deleted.

    Switvh willAttachRenderers to willRecalcStyle as the former is now called too late.

* svg/SVGUseElement.h:

LayoutTests:

* TestExpectations:

    Skip mathml/presentation/menclose-notation-attribute-change-value.html. It will be fixed by upcoming MathML refactoring.

* css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt:
* css3/viewport-percentage-lengths/viewport-percentage-lengths-resize-expected.txt:

    This is a progression.

* editing/mac/spelling/autocorrection-contraction-expected.txt:
* editing/mac/spelling/autocorrection-removing-underline-after-paste-expected.txt:
* editing/mac/spelling/autocorrection-removing-underline-expected.txt:
* editing/mac/spelling/autocorrection-simple-expected.txt:
* editing/style/remove-underline-from-stylesheet-expected.txt:
* editing/style/typing-style-003-expected.txt:

    Non-rendered whitespace related changes.

* platform/ios-simulator/TestExpectations:

    Skip fast/regions/position-writing-modes-in-variable-width-regions.html on iOS. Similar tests are mostly already skipped.

* platform/ios-simulator/editing/style/typing-style-003-expected.txt: Added.
* platform/mac-wk2/editing/mac/spelling/autocorrection-contraction-expected.txt:
* platform/mac/editing/inserting/editable-html-element-expected.txt:
* platform/mac/editing/inserting/editing-empty-divs-expected.txt:
* platform/mac/editing/inserting/insert-at-end-02-expected.txt:
* platform/mac/editing/pasteboard/4989774-expected.txt:
* platform/mac/editing/selection/4983858-expected.txt:

    Non-rendered whitespace related changes.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198943 268f45cc-cd09-0410-ab3c-d52691b4dbfc

46 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt
LayoutTests/css3/viewport-percentage-lengths/viewport-percentage-lengths-resize-expected.txt
LayoutTests/editing/mac/spelling/autocorrection-contraction-expected.txt
LayoutTests/editing/mac/spelling/autocorrection-removing-underline-after-paste-expected.txt
LayoutTests/editing/mac/spelling/autocorrection-removing-underline-expected.txt
LayoutTests/editing/mac/spelling/autocorrection-simple-expected.txt
LayoutTests/editing/style/remove-underline-from-stylesheet-expected.txt
LayoutTests/editing/style/typing-style-003-expected.txt
LayoutTests/fast/dom/beforeload/remove-bad-object-in-beforeload-listener-expected.txt
LayoutTests/fast/dom/beforeload/remove-flash-in-beforeload-listener-expected.txt
LayoutTests/platform/ios-simulator/TestExpectations
LayoutTests/platform/ios-simulator/editing/style/typing-style-003-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/editing/mac/spelling/autocorrection-contraction-expected.txt
LayoutTests/platform/mac/editing/inserting/editable-html-element-expected.txt
LayoutTests/platform/mac/editing/inserting/editing-empty-divs-expected.txt
LayoutTests/platform/mac/editing/inserting/insert-at-end-02-expected.txt
LayoutTests/platform/mac/editing/pasteboard/4989774-expected.txt
LayoutTests/platform/mac/editing/selection/4983858-expected.txt
LayoutTests/plugins/focus-expected.txt
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Node.cpp
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderElement.h
Source/WebCore/style/RenderTreePosition.cpp
Source/WebCore/style/RenderTreeUpdater.cpp [new file with mode: 0644]
Source/WebCore/style/RenderTreeUpdater.h [new file with mode: 0644]
Source/WebCore/style/StyleRelations.cpp
Source/WebCore/style/StyleRelations.h
Source/WebCore/style/StyleSharingResolver.cpp
Source/WebCore/style/StyleSharingResolver.h
Source/WebCore/style/StyleTreeResolver.cpp
Source/WebCore/style/StyleTreeResolver.h
Source/WebCore/style/StyleUpdate.cpp [new file with mode: 0644]
Source/WebCore/style/StyleUpdate.h [new file with mode: 0644]
Source/WebCore/svg/SVGElement.h
Source/WebCore/svg/SVGUseElement.cpp
Source/WebCore/svg/SVGUseElement.h

index 68a8800..a337c62 100644 (file)
@@ -1,3 +1,42 @@
+2016-03-31  Antti Koivisto  <antti@apple.com>
+
+        Separate render tree updating from style resolve
+        https://bugs.webkit.org/show_bug.cgi?id=155298
+
+        Reviewed by Andreas Kling.
+
+        * TestExpectations:
+
+            Skip mathml/presentation/menclose-notation-attribute-change-value.html. It will be fixed by upcoming MathML refactoring.
+
+        * css3/blending/repaint/blend-mode-isolate-stacking-context-expected.txt:
+        * css3/viewport-percentage-lengths/viewport-percentage-lengths-resize-expected.txt:
+
+            This is a progression.
+
+        * editing/mac/spelling/autocorrection-contraction-expected.txt:
+        * editing/mac/spelling/autocorrection-removing-underline-after-paste-expected.txt:
+        * editing/mac/spelling/autocorrection-removing-underline-expected.txt:
+        * editing/mac/spelling/autocorrection-simple-expected.txt:
+        * editing/style/remove-underline-from-stylesheet-expected.txt:
+        * editing/style/typing-style-003-expected.txt:
+
+            Non-rendered whitespace related changes.
+
+        * platform/ios-simulator/TestExpectations:
+
+            Skip fast/regions/position-writing-modes-in-variable-width-regions.html on iOS. Similar tests are mostly already skipped.
+
+        * platform/ios-simulator/editing/style/typing-style-003-expected.txt: Added.
+        * platform/mac-wk2/editing/mac/spelling/autocorrection-contraction-expected.txt:
+        * platform/mac/editing/inserting/editable-html-element-expected.txt:
+        * platform/mac/editing/inserting/editing-empty-divs-expected.txt:
+        * platform/mac/editing/inserting/insert-at-end-02-expected.txt:
+        * platform/mac/editing/pasteboard/4989774-expected.txt:
+        * platform/mac/editing/selection/4983858-expected.txt:
+
+            Non-rendered whitespace related changes.
+
 2016-03-31  Chris Fleizach  <cfleizach@apple.com>
 
         AX: <attachment> element not accessible
index f990b13..fef3c1d 100644 (file)
@@ -990,6 +990,9 @@ webkit.org/b/154686 inspector/indexeddb/requestDatabaseNames.html [ Skip ]
 storage/indexeddb/modern/exceed-open-file-limit.html [ Skip ]
 webkit.org/b/155028 storage/indexeddb/modern/256-open-databases.html [ Skip ]
 
+# Fixed by upcoming MathML refactoring
+webkit.org/b/155019 mathml/presentation/menclose-notation-attribute-change-value.html [ Skip ]
+
 ### END OF IndexedDB failures
 ########################################
 
index ce0354a..b443e22 100644 (file)
@@ -21,10 +21,10 @@ Test if unsetting a parent's stacking context correctly updates its parent isola
   (rect 48 290 60 60)
   (rect 28 290 60 60)
   (rect 48 290 60 60)
-  (rect 48 408 60 60)
-  (rect 48 408 60 60)
   (rect 28 526 60 60)
   (rect 48 526 60 60)
+  (rect 48 408 60 60)
+  (rect 48 408 60 60)
   (rect 48 644 60 60)
   (rect 68 644 60 60)
   (rect 48 644 60 60)
index 2f573f9..2e96a87 100644 (file)
@@ -17,19 +17,19 @@ PASS innerHeight is 600
 PASS getComputedStyle(test).fontSize is "30px"
 PASS getComputedStyle(test).width is "450px"
 PASS getComputedStyle(testpseudo, ':after').marginLeft is "120px"
-FAIL getComputedStyle(testpseudo, ':after').paddingRight should be 225px. Was 200px.
+PASS getComputedStyle(testpseudo, ':after').paddingRight is "225px"
 PASS innerWidth is 900
 PASS innerHeight is 640
 PASS getComputedStyle(test).fontSize is "32px"
 PASS getComputedStyle(test).width is "450px"
-FAIL getComputedStyle(testpseudo, ':after').marginLeft should be 128px. Was 120px.
-FAIL getComputedStyle(testpseudo, ':after').paddingRight should be 225px. Was 200px.
+PASS getComputedStyle(testpseudo, ':after').marginLeft is "128px"
+PASS getComputedStyle(testpseudo, ':after').paddingRight is "225px"
 PASS innerWidth is 500
 PASS innerHeight is 640
 PASS getComputedStyle(test).fontSize is "32px"
 PASS getComputedStyle(test).width is "250px"
-FAIL getComputedStyle(testpseudo, ':after').marginLeft should be 100px. Was 120px.
-FAIL getComputedStyle(testpseudo, ':after').paddingRight should be 160px. Was 200px.
+PASS getComputedStyle(testpseudo, ':after').marginLeft is "100px"
+PASS getComputedStyle(testpseudo, ':after').paddingRight is "160px"
 PASS innerWidth is 800
 PASS innerHeight is 600
 PASS getComputedStyle(test).fontSize is "30px"
index 6381e26..7fdf619 100644 (file)
@@ -279,4 +279,4 @@ layer at (0,0) size 800x600
           RenderText {#text} at (0,0) size 160x28
             text run at (0,0) width 154: "would' wouldn't"
             text run at (153,0) width 7: " "
-caret: position 16 of child 0 {#text} of child 5 {DIV} of child 3 {DIV} of body
+caret: position 16 of child 0 {#text} of child 6 {DIV} of child 3 {DIV} of body
index 94e48bd..ffef6c4 100644 (file)
@@ -82,4 +82,4 @@ layer at (0,0) size 800x600
             text run at (0,28) width 34: "baz"
         RenderBlock {DIV} at (14,70) size 756x28
           RenderBR {BR} at (0,0) size 0x28
-caret: position 0 of child 0 {BR} of child 4 {DIV} of child 5 {DIV} of body
+caret: position 0 of child 0 {BR} of child 5 {DIV} of child 5 {DIV} of body
index 6d5cb7d..fa8604f 100644 (file)
@@ -78,4 +78,4 @@ layer at (0,0) size 800x600
           RenderInline {SPAN} at (0,0) size 1x28
         RenderBlock {DIV} at (14,42) size 756x28
           RenderBR {BR} at (0,0) size 0x28
-caret: position 0 of child 0 {BR} of child 2 {DIV} of child 5 {DIV} of body
+caret: position 0 of child 0 {BR} of child 3 {DIV} of child 5 {DIV} of body
index 3694ae4..01c35ae 100644 (file)
@@ -137,4 +137,4 @@ layer at (0,0) size 800x600
         RenderBlock {DIV} at (14,42) size 756x28
           RenderText {#text} at (0,0) size 138x28
             text run at (0,0) width 138: "the notational,"
-caret: position 15 of child 0 {#text} of child 2 {DIV} of child 7 {DIV} of body
+caret: position 15 of child 0 {#text} of child 3 {DIV} of child 7 {DIV} of body
index ed1add7..4103c98 100644 (file)
@@ -76,5 +76,7 @@ This tests removing underline from stylesheet (.editing has underline). Because
 | "xxxxxx "
 | "<#selection-anchor>xxxxxx<#selection-focus>"
 | " xxxxxx"
+| "
+"
 | <span>
 |   id="test"
index 73cdc66..7256604 100644 (file)
@@ -52,10 +52,10 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 xxxxxxxxxxxxxxx
 execTypeCharacterCommand: x <span id="test"></span>
-execTypeCharacterCommand: xx<span id="test"></span>
-execTypeCharacterCommand: xxx<span id="test"></span>
-execBoldCommand: xxx<span id="test"></span>
-execTypeCharacterCommand: xxx<b>x</b><span id="test"></span>
+execTypeCharacterCommand: xx <span id="test"></span>
+execTypeCharacterCommand: xxx <span id="test"></span>
+execBoldCommand: xxx <span id="test"></span>
+execTypeCharacterCommand: xxx<b>x</b> <span id="test"></span>
 execTypeCharacterCommand: xxx<b>xx</b><span id="test"></span>
 execTypeCharacterCommand: xxx<b>xxx</b><span id="test"></span>
 execItalicCommand: xxx<b>xxx</b><span id="test"></span>
index 8a82410..c0e581e 100644 (file)
@@ -2053,6 +2053,7 @@ fast/regions/percentage-margins-mixed-ltr-dominant-regions.html [ ImageOnlyFailu
 fast/regions/percentage-margins-mixed-rtl-dominant-regions.html [ ImageOnlyFailure ]
 fast/regions/percentage-margins-rtl-variable-width-regions.html [ ImageOnlyFailure ]
 fast/regions/percentage-margins-variable-width-regions.html [ ImageOnlyFailure ]
+fast/regions/position-writing-modes-in-variable-width-regions.html [ ImageOnlyFailure ]
 fast/regions/positioning/fixed-in-named-flow-position-changed.html [ ImageOnlyFailure ]
 fast/regions/positioning/fixed-inside-fixed-in-named-flow.html [ ImageOnlyFailure ]
 fast/regions/positioning/fixed-inside-named-flow-zIndex.html [ ImageOnlyFailure ]
diff --git a/LayoutTests/platform/ios-simulator/editing/style/typing-style-003-expected.txt b/LayoutTests/platform/ios-simulator/editing/style/typing-style-003-expected.txt
new file mode 100644 (file)
index 0000000..73cdc66
--- /dev/null
@@ -0,0 +1,72 @@
+EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of DIV > BODY > HTML > #document to 3 of DIV > BODY > HTML > #document
+EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > DIV > BODY > HTML > #document to 1 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > DIV > BODY > HTML > #document to 1 of #text > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > DIV > BODY > HTML > #document to 2 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > DIV > BODY > HTML > #document to 2 of #text > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > DIV > BODY > HTML > #document to 3 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > B > DIV > BODY > HTML > #document to 1 of #text > B > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > B > DIV > BODY > HTML > #document to 1 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > B > DIV > BODY > HTML > #document to 1 of #text > B > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > B > DIV > BODY > HTML > #document to 2 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > B > DIV > BODY > HTML > #document to 2 of #text > B > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > B > DIV > BODY > HTML > #document to 3 of #text > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > B > DIV > BODY > HTML > #document to 1 of #text > I > B > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > I > B > DIV > BODY > HTML > #document to 1 of #text > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > B > DIV > BODY > HTML > #document to 1 of #text > I > B > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > I > B > DIV > BODY > HTML > #document to 2 of #text > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > I > B > DIV > BODY > HTML > #document to 2 of #text > I > B > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > I > B > DIV > BODY > HTML > #document to 3 of #text > I > B > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > DIV > BODY > HTML > #document to 1 of #text > I > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > I > DIV > BODY > HTML > #document to 1 of #text > I > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > DIV > BODY > HTML > #document to 1 of #text > I > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > I > DIV > BODY > HTML > #document to 2 of #text > I > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > I > DIV > BODY > HTML > #document to 2 of #text > I > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > I > DIV > BODY > HTML > #document to 3 of #text > I > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > DIV > BODY > HTML > #document to 1 of #text > DIV > BODY > HTML > #document toDOMRange:range from 1 of #text > DIV > BODY > HTML > #document to 1 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > DIV > BODY > HTML > #document to 1 of #text > DIV > BODY > HTML > #document toDOMRange:range from 2 of #text > DIV > BODY > HTML > #document to 2 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 2 of #text > DIV > BODY > HTML > #document to 2 of #text > DIV > BODY > HTML > #document toDOMRange:range from 3 of #text > DIV > BODY > HTML > #document to 3 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+xxxxxxxxxxxxxxx
+execTypeCharacterCommand: x <span id="test"></span>
+execTypeCharacterCommand: xx<span id="test"></span>
+execTypeCharacterCommand: xxx<span id="test"></span>
+execBoldCommand: xxx<span id="test"></span>
+execTypeCharacterCommand: xxx<b>x</b><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xx</b><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><span id="test"></span>
+execItalicCommand: xxx<b>xxx</b><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx<i>x</i></b><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx<i>xx</i></b><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx<i>xxx</i></b><span id="test"></span>
+execBoldCommand: xxx<b>xxx<i>xxx</i></b><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><i><b>xxx</b>x</i><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><i><b>xxx</b>xx</i><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><i><b>xxx</b>xxx</i><span id="test"></span>
+execItalicCommand: xxx<b>xxx</b><i><b>xxx</b>xxx</i><span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><i><b>xxx</b>xxx</i>x<span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><i><b>xxx</b>xxx</i>xx<span id="test"></span>
+execTypeCharacterCommand: xxx<b>xxx</b><i><b>xxx</b>xxx</i>xxx<span id="test"></span>
index 2944f7f..d06fc59 100644 (file)
@@ -259,4 +259,4 @@ layer at (0,0) size 800x600
           RenderText {#text} at (0,0) size 172x28
             text run at (0,0) width 166: "wouldn' wouldn't"
             text run at (165,0) width 7: " "
-caret: position 17 of child 0 {#text} of child 5 {DIV} of child 3 {DIV} of body
+caret: position 17 of child 0 {#text} of child 6 {DIV} of child 3 {DIV} of body
index 1923847..394ca3e 100644 (file)
@@ -22,7 +22,6 @@ layer at (0,0) size 800x600
           text run at (0,18) width 767: "inserting a paragraph separator doesn't split the body (inserting a paragraph separator usually splits/clones the enclosing"
           text run at (766,18) width 5: " "
           text run at (0,36) width 132: "block flow element)."
-        RenderText {#text} at (0,0) size 0x0
       RenderBlock {DIV} at (0,54) size 784x18
         RenderBR {BR} at (0,0) size 0x18
 caret: position 0 of child 0 {BR} of child 2 {DIV} of body
index cd9a7b5..c05a295 100644 (file)
@@ -65,7 +65,6 @@ layer at (0,0) size 800x600
       RenderBlock {DIV} at (0,230) size 708x22 [border: (1px dotted #0000FF)]
         RenderText {#text} at (1,1) size 8x18
           text run at (1,1) width 8: "c"
-        RenderText {#text} at (0,0) size 0x0
       RenderBlock {P} at (0,268) size 784x18
         RenderText {#text} at (0,0) size 240x18
           text run at (0,0) width 240: "This div contains a self-closing p tag."
@@ -81,6 +80,5 @@ layer at (0,0) size 800x600
         RenderBlock (anonymous) at (1,1) size 706x18
           RenderText {#text} at (0,0) size 8x18
             text run at (0,0) width 8: "c"
-          RenderText {#text} at (0,0) size 0x0
         RenderBlock {P} at (1,35) size 706x0
 caret: position 1 of child 0 {#text} of child 21 {DIV} of body
index 3f8e292..05690fc 100644 (file)
@@ -29,5 +29,4 @@ layer at (0,0) size 800x600
         RenderBlock (anonymous) at (2,46) size 780x18
           RenderText {#text} at (0,0) size 8x18
             text run at (0,0) width 8: "x"
-          RenderText {#text} at (0,0) size 0x0
 caret: position 1 of child 5 {#text} of child 5 {DIV} of body
index 50ef27d..97488f3 100644 (file)
@@ -12,6 +12,4 @@ layer at (0,0) size 800x600
         text run at (634,103) width 102: "You should see"
         text run at (735,103) width 5: " "
         text run at (0,121) width 364: "several pictures above all in the same line/paragraph."
-      RenderText {#text} at (0,0) size 0x0
-      RenderText {#text} at (0,0) size 0x0
 caret: position 164 of child 4 {#text} of body
index 23054e1..56a195c 100644 (file)
@@ -10,7 +10,6 @@ layer at (0,0) size 800x600
           text run at (716,0) width 65: "paragraph"
           text run at (780,0) width 4: " "
           text run at (0,18) width 165: "below should be selected:"
-        RenderText {#text} at (0,0) size 0x0
       RenderBlock {DIV} at (0,36) size 784x18
         RenderText {#text} at (0,0) size 22x18
           text run at (0,0) width 22: "foo"
index b9d1719..269ca2c 100644 (file)
@@ -24,3 +24,4 @@ Test for bug 32292: "Unable to focus on embedded plugins such as Flash via javas
 This tests focusing Embeds and Objects. See LayoutTests/java for Applet elements.
 
    Fallback contents.     Fallback contents. Fallback contents.      
+
index daafb7d..c62a9d2 100644 (file)
@@ -2627,12 +2627,14 @@ set(WebCore_SOURCES
     style/IdChangeInvalidation.cpp
     style/InlineTextBoxStyle.cpp
     style/RenderTreePosition.cpp
+    style/RenderTreeUpdater.cpp
     style/StyleChange.cpp
     style/StyleFontSizeFunctions.cpp
     style/StyleRelations.cpp
     style/StyleResolveForDocument.cpp
     style/StyleSharingResolver.cpp
     style/StyleTreeResolver.cpp
+    style/StyleUpdate.cpp
 
     svg/SVGAElement.cpp
     svg/SVGAltGlyphDefElement.cpp
index 67b6121..2206947 100644 (file)
@@ -1,3 +1,218 @@
+2016-03-31  Antti Koivisto  <antti@apple.com>
+
+        Separate render tree updating from style resolve
+        https://bugs.webkit.org/show_bug.cgi?id=155298
+
+        Reviewed by Andreas Kling.
+
+        This patch splits computing document style and applying the results into two distinct steps:
+
+        Style::TreeResolver::resolve()
+                |
+                | Style::Update
+                V
+        RenderTreeUpdater::commit()
+
+        Style::TreeResolver::resolve() returns a Style::Update object that contains all the changes to be made
+        for the whole composed tree. RenderTreeUpdater then applies the changes updating, building or tearing
+        down portions of the render tree as needed.
+
+        Style::Update consists of a map that contains new style for each newly resolved element along with some
+        metadata. A separate map contains text nodes that require reconstruction. It also tracks change roots so
+        RenderTreeUpdater needs to traverse the changed subtrees only.
+
+        The patch eliminates the recursive render tree build code path replacing it with iterative functions.
+
+        This will enable future optimizations. For example we won't need to commit to immediate rendering
+        changes simply because some script or internal function requires up-to-date style.
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::State::State):
+        (WebCore::StyleResolver::styleForElement):
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::setOverrideDocumentElementStyle):
+        (WebCore::StyleResolver::State::State):
+
+            Root element style is needed for resolving other elements. Add a way to provide it without looking
+            into active document style.
+
+        * dom/Document.cpp:
+        (WebCore::Document::recalcStyle):
+
+            Resolve the document style and commit it immediately (for now).
+
+        (WebCore::Document::styleForElementIgnoringPendingStylesheets):
+        * dom/Document.h:
+        (WebCore::Document::setNeedsNotifyRemoveAllPendingStylesheet):
+        (WebCore::Document::inStyleRecalc):
+        (WebCore::Document::inRenderTreeUpdate):
+        * dom/Element.cpp:
+        (WebCore::Element::setChildIndex):
+
+            Setting the unique bit is now done by style relations update code.
+
+        * dom/Node.cpp:
+        (WebCore::Node::setNeedsStyleRecalc):
+
+            Prevent spurious style invalidation during render tree updating.
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::styleDidChange):
+
+            Capturing body element color for color:-webkit-text is now done by TreeResolver.
+
+        * rendering/RenderElement.h:
+        (WebCore::RenderElement::setAnimatableStyle): Deleted.
+
+            No longer used.
+
+        * style/RenderTreePosition.cpp:
+        (WebCore::RenderTreePosition::nextSiblingRenderer):
+
+            Skip over non-rendered slot elements.
+
+        * style/RenderTreeUpdater.cpp: Added.
+        (WebCore::RenderTreeUpdater::Parent::Parent):
+        (WebCore::RenderTreeUpdater::RenderTreeUpdater):
+        (WebCore::hasDisplayContents):
+        (WebCore::findRenderingRoot):
+        (WebCore::RenderTreeUpdater::commit):
+
+            Call updateRenderTree for each change root.
+
+        (WebCore::shouldCreateRenderer):
+        (WebCore::RenderTreeUpdater::updateRenderTree):
+
+            Iteratively traverse the composed tree starting for a change root.
+            Apply the changes calling updateElementRenderer and updateTextRenderer as needed.
+            Enter subtrees that haves changes to apply.
+
+        (WebCore::RenderTreeUpdater::renderTreePosition):
+
+            We may not create renderers for all elements (<slot> or more generally display:contents) that
+            have rendered descendants. Search the parent stack to find the valid position.
+
+        (WebCore::RenderTreeUpdater::pushParent):
+        (WebCore::RenderTreeUpdater::popParent):
+        (WebCore::RenderTreeUpdater::popParentsToDepth):
+
+            Maintain parent stack.
+
+        (WebCore::pseudoStyleCacheIsInvalid):
+        (WebCore::RenderTreeUpdater::updateElementRenderer):
+
+            Create, delete or update the renderer.
+
+        (WebCore::moveToFlowThreadIfNeeded):
+        (WebCore::RenderTreeUpdater::createRenderer):
+        (WebCore::textRendererIsNeeded):
+        (WebCore::createTextRenderer):
+        (WebCore::RenderTreeUpdater::updateTextRenderer):
+        (WebCore::RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded):
+
+            This is moved from TreeResolver.
+
+        (WebCore::needsPseudoElement):
+        (WebCore::RenderTreeUpdater::updateBeforeOrAfterPseudoElement):
+
+            Pseudo elements are handled entirely during render tree construction. Compute their style and
+            create or delete them as needed.
+
+        * style/RenderTreeUpdater.h: Added.
+        (WebCore::RenderTreeUpdater::parent):
+        * style/StyleRelations.cpp:
+        (WebCore::Style::commitRelationsToRenderStyle):
+        (WebCore::Style::commitRelations):
+
+            Commit to Style::Update instead of the document if needed.
+
+        (WebCore::Style::commitRelationsToDocument): Deleted.
+        * style/StyleRelations.h:
+        * style/StyleSharingResolver.cpp:
+        (WebCore::Style::elementHasDirectionAuto):
+        (WebCore::Style::SharingResolver::resolve):
+
+            Fetch the shareable style from Style::Update instead of the active document style.
+
+        (WebCore::Style::SharingResolver::findSibling):
+        (WebCore::Style::SharingResolver::canShareStyleWithElement):
+        * style/StyleSharingResolver.h:
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::Parent::Parent):
+
+            No need for render tree position anymore.
+
+        (WebCore::Style::TreeResolver::popScope):
+        (WebCore::Style::TreeResolver::styleForElement):
+        (WebCore::Style::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded):
+        (WebCore::Style::createTextRendererIfNeeded):
+        (WebCore::Style::updateTextRendererAfterContentChange):
+        (WebCore::Style::resetStyleForNonRenderedDescendants):
+        (WebCore::Style::detachChildren):
+        (WebCore::Style::detachSlotAssignees):
+        (WebCore::Style::detachRenderTree):
+        (WebCore::Style::TreeResolver::resolveElement):
+
+            Just resolve the style and return it, no more applying or entering render tree construction code paths.
+
+        (WebCore::Style::resolveTextNode):
+        (WebCore::Style::elementImplicitVisibility):
+        (WebCore::Style::TreeResolver::pushParent):
+        (WebCore::Style::TreeResolver::popParent):
+        (WebCore::Style::TreeResolver::popParentsToDepth):
+        (WebCore::Style::shouldResolvePseudoElement):
+        (WebCore::Style::TreeResolver::resolveComposedTree):
+
+            Add style changes to Style::Update.
+
+        (WebCore::Style::TreeResolver::resolve):
+
+            Return Style::Update object if non-empty.
+
+        (WebCore::Style::postResolutionCallbackQueue):
+        (WebCore::Style::shouldCreateRenderer): Deleted.
+        (WebCore::Style::moveToFlowThreadIfNeeded): Deleted.
+        (WebCore::Style::TreeResolver::createRenderer): Deleted.
+        (WebCore::Style::TreeResolver::createRenderTreeForChildren): Deleted.
+        (WebCore::Style::TreeResolver::createRenderTreeForShadowRoot): Deleted.
+        (WebCore::Style::beforeOrAfterPseudoElement): Deleted.
+        (WebCore::Style::setBeforeOrAfterPseudoElement): Deleted.
+        (WebCore::Style::clearBeforeOrAfterPseudoElement): Deleted.
+        (WebCore::Style::needsPseudoElement): Deleted.
+        (WebCore::Style::TreeResolver::createRenderTreeForBeforeOrAfterPseudoElement): Deleted.
+        (WebCore::Style::TreeResolver::createRenderTreeForSlotAssignees): Deleted.
+        (WebCore::Style::TreeResolver::createRenderTreeRecursively): Deleted.
+        (WebCore::Style::pseudoStyleCacheIsInvalid): Deleted.
+        (WebCore::Style::TreeResolver::resolveBeforeOrAfterPseudoElement): Deleted.
+
+            Remove the recursive render tree building code path.
+
+        * style/StyleTreeResolver.h:
+        (WebCore::Style::TreeResolver::scope):
+        * style/StyleUpdate.cpp: Added.
+        (WebCore::Style::Update::Update):
+        (WebCore::Style::Update::elementUpdate):
+        (WebCore::Style::Update::textUpdate):
+        (WebCore::Style::Update::elementStyle):
+        (WebCore::Style::Update::addElement):
+        (WebCore::Style::Update::addText):
+        (WebCore::Style::Update::addPossibleRoot):
+        * style/StyleUpdate.h: Added.
+        (WebCore::Style::Update::roots):
+        (WebCore::Style::Update::document):
+        * svg/SVGElement.h:
+        (WebCore::SVGElement::updateRelativeLengthsInformation):
+        * svg/SVGUseElement.cpp:
+        (WebCore::SVGUseElement::svgAttributeChanged):
+        (WebCore::SVGUseElement::willRecalcStyle):
+        (WebCore::SVGUseElement::willAttachRenderers): Deleted.
+
+            Switvh willAttachRenderers to willRecalcStyle as the former is now called too late.
+
+        * svg/SVGUseElement.h:
+
 2016-03-31  Chris Fleizach  <cfleizach@apple.com>
 
         AX: <attachment> element not accessible
index 4661db0..955db8b 100644 (file)
                E424A3A01330DF1E00CF6DC9 /* LegacyTileGridTile.mm in Sources */ = {isa = PBXBuildFile; fileRef = E424A39F1330DF1E00CF6DC9 /* LegacyTileGridTile.mm */; };
                E425A49A18292B840020CFCF /* CollectionIndexCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E425A49918292B840020CFCF /* CollectionIndexCache.h */; };
                E4295FA412B0614E00D1ACE0 /* ResourceLoadPriority.h in Headers */ = {isa = PBXBuildFile; fileRef = E4295FA312B0614E00D1ACE0 /* ResourceLoadPriority.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E42E76DA1C7AF76C00E3614D /* StyleUpdate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E42E76D91C7AF76C00E3614D /* StyleUpdate.cpp */; };
+               E42E76DC1C7AF77600E3614D /* StyleUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = E42E76DB1C7AF77600E3614D /* StyleUpdate.h */; };
                E43105B816750F0C00DB2FB8 /* NodeTraversal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43105B716750F0C00DB2FB8 /* NodeTraversal.cpp */; };
                E43105BB16750F1600DB2FB8 /* NodeTraversal.h in Headers */ = {isa = PBXBuildFile; fileRef = E43105BA16750F1600DB2FB8 /* NodeTraversal.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E43A023B17EB370A004CDD25 /* RenderElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E43A023A17EB370A004CDD25 /* RenderElement.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E45390490EAFD637003695C8 /* WebCoreSystemInterfaceIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = E45390380EAFD637003695C8 /* WebCoreSystemInterfaceIOS.mm */; };
                E453904D0EAFD637003695C8 /* WidgetIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = E453903C0EAFD637003695C8 /* WidgetIOS.mm */; };
                E45390AE0EAFF4B5003695C8 /* SystemMemoryIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E45390AD0EAFF4B5003695C8 /* SystemMemoryIOS.cpp */; };
+               E46180291C8A06CD0026C02C /* RenderTreeUpdater.h in Headers */ = {isa = PBXBuildFile; fileRef = E46180281C8A06CD0026C02C /* RenderTreeUpdater.h */; };
+               E461802B1C8A06D90026C02C /* RenderTreeUpdater.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E461802A1C8A06D90026C02C /* RenderTreeUpdater.cpp */; };
                E461802D1C8DD2900026C02C /* StyleRelations.h in Headers */ = {isa = PBXBuildFile; fileRef = E461802C1C8DD2900026C02C /* StyleRelations.h */; };
                E461802F1C8DD4D20026C02C /* StyleRelations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E461802E1C8DD4D20026C02C /* StyleRelations.cpp */; };
                E461D65D1BB0C7F000CB5645 /* AuthorStyleSheets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E461D65C1BB0C7F000CB5645 /* AuthorStyleSheets.cpp */; };
                E424A39F1330DF1E00CF6DC9 /* LegacyTileGridTile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LegacyTileGridTile.mm; sourceTree = "<group>"; };
                E425A49918292B840020CFCF /* CollectionIndexCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionIndexCache.h; sourceTree = "<group>"; };
                E4295FA312B0614E00D1ACE0 /* ResourceLoadPriority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceLoadPriority.h; sourceTree = "<group>"; };
+               E42E76D91C7AF76C00E3614D /* StyleUpdate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleUpdate.cpp; sourceTree = "<group>"; };
+               E42E76DB1C7AF77600E3614D /* StyleUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleUpdate.h; sourceTree = "<group>"; };
                E43105B716750F0C00DB2FB8 /* NodeTraversal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodeTraversal.cpp; sourceTree = "<group>"; };
                E43105BA16750F1600DB2FB8 /* NodeTraversal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeTraversal.h; sourceTree = "<group>"; };
                E43A023A17EB370A004CDD25 /* RenderElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderElement.h; sourceTree = "<group>"; };
                E45390380EAFD637003695C8 /* WebCoreSystemInterfaceIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreSystemInterfaceIOS.mm; sourceTree = "<group>"; };
                E453903C0EAFD637003695C8 /* WidgetIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WidgetIOS.mm; sourceTree = "<group>"; };
                E45390AD0EAFF4B5003695C8 /* SystemMemoryIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemMemoryIOS.cpp; sourceTree = "<group>"; };
+               E46180281C8A06CD0026C02C /* RenderTreeUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeUpdater.h; sourceTree = "<group>"; };
+               E461802A1C8A06D90026C02C /* RenderTreeUpdater.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeUpdater.cpp; sourceTree = "<group>"; };
                E461802C1C8DD2900026C02C /* StyleRelations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleRelations.h; sourceTree = "<group>"; };
                E461802E1C8DD4D20026C02C /* StyleRelations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleRelations.cpp; sourceTree = "<group>"; };
                E461D65C1BB0C7F000CB5645 /* AuthorStyleSheets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AuthorStyleSheets.cpp; sourceTree = "<group>"; };
                                1C0106FF192594DF008A4201 /* InlineTextBoxStyle.h */,
                                5824ABA81AE849C8009074B7 /* RenderTreePosition.cpp */,
                                5824ABA91AE849C8009074B7 /* RenderTreePosition.h */,
+                               E461802A1C8A06D90026C02C /* RenderTreeUpdater.cpp */,
+                               E46180281C8A06CD0026C02C /* RenderTreeUpdater.h */,
                                E401E0A51C3C0CF700F34D10 /* StyleChange.cpp */,
                                E401E0A31C3C0B8300F34D10 /* StyleChange.h */,
                                E4D58EB617B4ED8900CBDCA8 /* StyleFontSizeFunctions.cpp */,
                                E47A3AC41C5EAC7900CCBFA7 /* StyleSharingResolver.h */,
                                E4DEAA1517A93DC3000E0430 /* StyleTreeResolver.cpp */,
                                E4DEAA1617A93DC3000E0430 /* StyleTreeResolver.h */,
+                               E42E76D91C7AF76C00E3614D /* StyleUpdate.cpp */,
+                               E42E76DB1C7AF77600E3614D /* StyleUpdate.h */,
                        );
                        path = style;
                        sourceTree = "<group>";
                                5C4304B1191AC908000E2BC0 /* EXTShaderTextureLOD.h in Headers */,
                                7728694F14F8882500F484DC /* EXTTextureFilterAnisotropic.h in Headers */,
                                A75E8B890E1DE2D6007F2481 /* FEBlend.h in Headers */,
+                               E46180291C8A06CD0026C02C /* RenderTreeUpdater.h in Headers */,
                                A75E8B8B0E1DE2D6007F2481 /* FEColorMatrix.h in Headers */,
                                A75E8B8D0E1DE2D6007F2481 /* FEComponentTransfer.h in Headers */,
                                A75E8B8F0E1DE2D6007F2481 /* FEComposite.h in Headers */,
                                A8EA79F70A1916DF00A8EF5F /* HTMLDListElement.h in Headers */,
                                93F198E508245E59001E9ABC /* HTMLDocument.h in Headers */,
                                977B3867122883E900B81FF8 /* HTMLDocumentParser.h in Headers */,
+                               E42E76DC1C7AF77600E3614D /* StyleUpdate.h in Headers */,
                                93309DE8099E64920056E581 /* htmlediting.h in Headers */,
                                93F198E608245E59001E9ABC /* HTMLElement.h in Headers */,
                                A17C81230F2A5CF7005DAAEB /* HTMLElementFactory.h in Headers */,
                                A84EBD780CB8C89200079609 /* JSStyleSheetListCustom.cpp in Sources */,
                                E1FF8F64180745D800132674 /* JSSubtleCrypto.cpp in Sources */,
                                E1FF8F681807460800132674 /* JSSubtleCryptoCustom.cpp in Sources */,
+                               E461802B1C8A06D90026C02C /* RenderTreeUpdater.cpp in Sources */,
                                B20111070AB7740500DB0E68 /* JSSVGAElement.cpp in Sources */,
                                24D9129113CA951E00D21915 /* JSSVGAltGlyphDefElement.cpp in Sources */,
                                6515EC910D9723FF0063D49A /* JSSVGAltGlyphElement.cpp in Sources */,
                                0F43C85D189E10CF00019AE2 /* PerformanceTiming.cpp in Sources */,
                                FD581FB41520F93B003A7A75 /* PeriodicWave.cpp in Sources */,
                                49D5DC2D0F423A73008F20FD /* PerspectiveTransformOperation.cpp in Sources */,
+                               E42E76DA1C7AF76C00E3614D /* StyleUpdate.cpp in Sources */,
                                D0FF2A5D11F8C45A007E74E0 /* PingLoader.cpp in Sources */,
                                CD7D33431C7A123F00041293 /* PixelBufferConformerCV.cpp in Sources */,
                                0FDF45A71BD1C6FD00E4FA8C /* PlatformCAAnimation.cpp in Sources */,
index af78b7b..f2f2852 100644 (file)
@@ -335,7 +335,7 @@ void StyleResolver::sweepMatchedPropertiesCache()
     m_matchedPropertiesCacheAdditionsSinceLastSweep = 0;
 }
 
-StyleResolver::State::State(Element& element, RenderStyle* parentStyle, const RenderRegion* regionForStyling, const SelectorFilter* selectorFilter)
+StyleResolver::State::State(Element& element, RenderStyle* parentStyle, RenderStyle* documentElementStyle, const RenderRegion* regionForStyling, const SelectorFilter* selectorFilter)
     : m_element(&element)
     , m_parentStyle(parentStyle)
     , m_regionForStyling(regionForStyling)
@@ -348,7 +348,10 @@ StyleResolver::State::State(Element& element, RenderStyle* parentStyle, const Re
 
     auto& document = element.document();
     auto* documentElement = document.documentElement();
-    m_rootElementStyle = (!documentElement || documentElement == &element) ? document.renderStyle() : documentElement->renderStyle();
+    if (!documentElement || documentElement == &element)
+        m_rootElementStyle = document.renderStyle();
+    else
+        m_rootElementStyle = documentElementStyle ? documentElementStyle : documentElement->renderStyle();
 
     updateConversionData();
 }
@@ -375,7 +378,7 @@ ElementStyle StyleResolver::styleForElement(Element& element, RenderStyle* paren
 {
     RELEASE_ASSERT(!m_inLoadPendingImages);
 
-    m_state = State(element, parentStyle, regionForStyling, selectorFilter);
+    m_state = State(element, parentStyle, m_overrideDocumentElementStyle.get(), regionForStyling, selectorFilter);
     State& state = m_state;
 
     if (state.parentStyle()) {
index de06a84..381ef41 100644 (file)
@@ -164,6 +164,8 @@ public:
 
     const MediaQueryEvaluator& mediaQueryEvaluator() const { return *m_medium; }
 
+    void setOverrideDocumentElementStyle(RenderStyle* style) { m_overrideDocumentElementStyle = style; }
+
 private:
     Ref<RenderStyle> styleForKeyframe(const RenderStyle*, const StyleKeyframe*, KeyframeValue&);
 
@@ -359,7 +361,7 @@ public:
     class State {
     public:
         State() { }
-        State(Element&, RenderStyle* parentStyle, const RenderRegion* regionForStyling = nullptr, const SelectorFilter* = nullptr);
+        State(Element&, RenderStyle* parentStyle, RenderStyle* documentElementStyle = nullptr, const RenderRegion* regionForStyling = nullptr, const SelectorFilter* = nullptr);
 
     public:
         void clear();
@@ -524,6 +526,8 @@ private:
 
     bool m_matchAuthorAndUserStyles;
 
+    RefPtr<RenderStyle> m_overrideDocumentElementStyle;
+
     Vector<std::unique_ptr<MediaQueryResult>> m_viewportDependentMediaQueryResults;
 
 #if ENABLE(CSS_DEVICE_ADAPTATION)
index 0cfa005..f4ddca2 100644 (file)
 #include "ProcessingInstruction.h"
 #include "RenderChildIterator.h"
 #include "RenderLayerCompositor.h"
+#include "RenderTreeUpdater.h"
 #include "RenderView.h"
 #include "RenderWidget.h"
 #include "ResourceLoadObserver.h"
@@ -1926,15 +1927,22 @@ void Document::recalcStyle(Style::Change change)
         }
 
         Style::TreeResolver resolver(*this);
-        resolver.resolve(change);
-
-        updatedCompositingLayers = frameView.updateCompositingLayersAfterStyleChange();
+        auto styleUpdate = resolver.resolve(change);
 
         clearNeedsStyleRecalc();
         clearChildNeedsStyleRecalc();
         unscheduleStyleRecalc();
 
         m_inStyleRecalc = false;
+
+        if (styleUpdate) {
+            TemporaryChange<bool> inRenderTreeUpdate(m_inRenderTreeUpdate, true);
+
+            RenderTreeUpdater updater(*this);
+            updater.commit(WTFMove(styleUpdate));
+        }
+
+        updatedCompositingLayers = frameView.updateCompositingLayersAfterStyleChange();
     }
 
     // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
@@ -2052,7 +2060,10 @@ Ref<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element& el
     TemporaryChange<bool> change(m_ignorePendingStylesheets, true);
     auto elementStyle = element.resolveStyle(parentStyle);
 
-    Style::commitRelationsToDocument(WTFMove(elementStyle.relations));
+    if (elementStyle.relations) {
+        Style::Update emptyUpdate(*this);
+        Style::commitRelations(WTFMove(elementStyle.relations), emptyUpdate);
+    }
 
     return WTFMove(elementStyle.renderStyle);
 }
index d180a90..47e79ee 100644 (file)
@@ -1244,7 +1244,8 @@ public:
     void setNeedsNotifyRemoveAllPendingStylesheet() { m_needsNotifyRemoveAllPendingStylesheet = true; }
     void clearStyleResolver();
 
-    bool inStyleRecalc() { return m_inStyleRecalc; }
+    bool inStyleRecalc() const { return m_inStyleRecalc; }
+    bool inRenderTreeUpdate() const { return m_inRenderTreeUpdate; }
 
     // Return a Locale for the default locale if the argument is null or empty.
     Locale& getCachedLocale(const AtomicString& locale = nullAtom);
@@ -1508,6 +1509,7 @@ private:
     bool m_pendingStyleRecalcShouldForce;
     bool m_inStyleRecalc;
     bool m_closeAfterStyleRecalc;
+    bool m_inRenderTreeUpdate { false };
 
     bool m_gotoAnchorNeededAfterStylesheetsLoad;
     bool m_isDNSPrefetchEnabled;
index e904e9b..22ce6b7 100644 (file)
@@ -2564,8 +2564,6 @@ void Element::setChildrenAffectedByPropertyBasedBackwardPositionalRules()
 void Element::setChildIndex(unsigned index)
 {
     ElementRareData& rareData = ensureElementRareData();
-    if (RenderStyle* style = renderStyle())
-        style->setUnique();
     rareData.setChildIndex(index);
 }
 
index 0c7cc07..78463d3 100644 (file)
@@ -772,6 +772,10 @@ void Node::setNeedsStyleRecalc(StyleChangeType changeType)
     if (!inRenderedDocument())
         return;
 
+    // FIXME: This should eventually be an ASSERT.
+    if (document().inRenderTreeUpdate())
+        return;
+
     StyleChangeType existingChangeType = styleChangeType();
     if (changeType > existingChangeType)
         setStyleChange(changeType);
index d274a9b..bb801b5 100644 (file)
@@ -381,10 +381,6 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
     bool isBodyRenderer = isBody();
     bool isDocElementRenderer = isDocumentElementRenderer();
 
-    // Set the text color if we're the body.
-    if (isBodyRenderer)
-        document().setTextColor(newStyle.visitedDependentColor(CSSPropertyColor));
-
     if (isDocElementRenderer || isBodyRenderer) {
         // Propagate the new writing mode and direction up to the RenderView.
         auto* documentElementRenderer = document().documentElement()->renderer();
index 02e5449..ed2edb2 100644 (file)
@@ -50,9 +50,6 @@ public:
     // continue even if the style isn't different from the current style.
     void setStyle(Ref<RenderStyle>&&, StyleDifference minimalStyleDifference = StyleDifferenceEqual);
 
-    // Called to update a style that is allowed to trigger animations.
-    void setAnimatableStyle(Ref<RenderStyle>&&, StyleDifference minimalStyleDifference);
-
     // The pseudo element style can be cached or uncached.  Use the cached method if the pseudo element doesn't respect
     // any pseudo classes (and therefore has no concept of changing state).
     RenderStyle* getCachedPseudoStyle(PseudoId, RenderStyle* parentStyle = nullptr) const;
@@ -343,15 +340,6 @@ private:
     static bool s_noLongerAffectsParentBlock;
 };
 
-inline void RenderElement::setAnimatableStyle(Ref<RenderStyle>&& style, StyleDifference minimalStyleDifference)
-{
-    Ref<RenderStyle> animatedStyle = WTFMove(style);
-    if (animation().updateAnimations(*this, animatedStyle, animatedStyle))
-        minimalStyleDifference = std::max(minimalStyleDifference, StyleDifferenceRecompositeLayer);
-    
-    setStyle(WTFMove(animatedStyle), minimalStyleDifference);
-}
-
 inline void RenderElement::setAncestorLineBoxDirty(bool f)
 {
     m_ancestorLineBoxDirty = f;
index cb038e8..d5c73d4 100644 (file)
@@ -27,6 +27,7 @@
 #include "RenderTreePosition.h"
 
 #include "ComposedTreeIterator.h"
+#include "HTMLSlotElement.h"
 #include "PseudoElement.h"
 #include "RenderObject.h"
 #include "ShadowRoot.h"
@@ -82,13 +83,22 @@ RenderObject* RenderTreePosition::nextSiblingRenderer(const Node& node) const
     if (node.isAfterPseudoElement())
         return nullptr;
 
-    auto composedChildren = composedTreeChildren(*parentElement);
+    auto composedDescendants = composedTreeDescendants(*parentElement);
+    auto it = node.isBeforePseudoElement() ? composedDescendants.begin() : composedDescendants.at(node);
+    auto end = composedDescendants.end();
 
-    auto it = node.isBeforePseudoElement() ? composedChildren.begin() : composedChildren.at(node);
-    for (auto end = composedChildren.end(); it != end; ++it) {
-        RenderObject* renderer = it->renderer();
+    while (it != end) {
+        auto& node = *it;
+        bool hasDisplayContents = is<HTMLSlotElement>(node);
+        if (hasDisplayContents) {
+            it.traverseNext();
+            continue;
+        }
+        RenderObject* renderer = node.renderer();
         if (renderer && !isRendererReparented(*renderer))
             return renderer;
+        
+        it.traverseNextSkippingChildren();
     }
     if (PseudoElement* after = parentElement->afterPseudoElement())
         return after->renderer();
diff --git a/Source/WebCore/style/RenderTreeUpdater.cpp b/Source/WebCore/style/RenderTreeUpdater.cpp
new file mode 100644 (file)
index 0000000..91062be
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RenderTreeUpdater.h"
+
+#include "AXObjectCache.h"
+#include "ComposedTreeAncestorIterator.h"
+#include "ComposedTreeIterator.h"
+#include "Document.h"
+#include "Element.h"
+#include "FlowThreadController.h"
+#include "HTMLSlotElement.h"
+#include "InspectorInstrumentation.h"
+#include "PseudoElement.h"
+#include "RenderFullScreen.h"
+#include "RenderNamedFlowThread.h"
+#include "StyleResolver.h"
+#include "StyleTreeResolver.h"
+
+namespace WebCore {
+
+RenderTreeUpdater::Parent::Parent(ContainerNode& root)
+    : element(is<Document>(root) ? nullptr : downcast<Element>(&root))
+    , renderTreePosition(RenderTreePosition(*root.renderer()))
+{
+}
+
+RenderTreeUpdater::Parent::Parent(Element& element, Style::Change styleChange)
+    : element(&element)
+    , styleChange(styleChange)
+    , renderTreePosition(element.renderer() ? makeOptional(RenderTreePosition(*element.renderer())) : Nullopt)
+{
+}
+
+
+RenderTreeUpdater::RenderTreeUpdater(Document& document)
+    : m_document(document)
+{
+}
+
+// Slots have implicit display:contents until it is supported for reals.
+static bool hasDisplayContents(const Node& node)
+{
+    return is<HTMLSlotElement>(node);
+}
+
+static ContainerNode& findRenderingRoot(ContainerNode& node)
+{
+    auto& document = node.document();
+    for (ComposedTreeAncestorIterator it(document, node), end(document); it != end; ++it) {
+        if (it->renderer())
+            return *it;
+        ASSERT(hasDisplayContents(*it));
+    }
+    ASSERT_NOT_REACHED();
+    return document;
+}
+
+void RenderTreeUpdater::commit(std::unique_ptr<const Style::Update> styleUpdate)
+{
+    ASSERT(&m_document == &styleUpdate->document());
+
+    if (!m_document.shouldCreateRenderers())
+        return;
+
+    m_styleUpdate = WTFMove(styleUpdate);
+
+    for (auto* root : m_styleUpdate->roots())
+        updateRenderTree(findRenderingRoot(*root));
+
+    m_styleUpdate = nullptr;
+}
+
+static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
+{
+    if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
+        return false;
+    if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
+        return false;
+    return true;
+}
+
+void RenderTreeUpdater::updateRenderTree(ContainerNode& root)
+{
+    ASSERT(root.renderer());
+    ASSERT(m_parentStack.isEmpty());
+
+    m_parentStack.append(Parent(root));
+
+    auto descendants = composedTreeDescendants(root);
+    auto it = descendants.begin();
+    auto end = descendants.end();
+
+    // FIXME: SVG <use> element may cause tree mutations during style recalc.
+    it.dropAssertions();
+
+    while (it != end) {
+        popParentsToDepth(it.depth());
+
+        auto& node = *it;
+
+        if (auto* renderer = node.renderer())
+            renderTreePosition().invalidateNextSibling(*renderer);
+
+        if (is<Text>(node)) {
+            auto& text = downcast<Text>(node);
+            if (parent().styleChange == Style::Detach || m_styleUpdate->textUpdate(text) || m_invalidatedWhitespaceOnlyTextSiblings.contains(&text))
+                updateTextRenderer(text);
+
+            it.traverseNextSkippingChildren();
+            continue;
+        }
+
+        auto& element = downcast<Element>(node);
+
+        auto* elementUpdate = m_styleUpdate->elementUpdate(element);
+
+        auto changeType = Style::NoChange;
+        if (elementUpdate) {
+            if (hasDisplayContents(element)) {
+                if (!shouldCreateRenderer(element, renderTreePosition().parent())) {
+                    it.traverseNextSkippingChildren();
+                    continue;
+                }
+                pushParent(element, parent().styleChange);
+                it.traverseNext();
+                continue;
+            }
+
+            updateElementRenderer(element, *elementUpdate);
+            changeType = elementUpdate->change;
+        }
+
+        if (!element.renderer() || !elementUpdate) {
+            it.traverseNextSkippingChildren();
+            continue;
+        }
+
+        pushParent(element, changeType);
+
+        it.traverseNext();
+    }
+
+    popParentsToDepth(0);
+
+    m_invalidatedWhitespaceOnlyTextSiblings.clear();
+}
+
+RenderTreePosition& RenderTreeUpdater::renderTreePosition()
+{
+    for (unsigned i = m_parentStack.size(); i; --i) {
+        if (auto& position = m_parentStack[i - 1].renderTreePosition)
+            return *position;
+    }
+    ASSERT_NOT_REACHED();
+    return *m_parentStack.last().renderTreePosition;
+}
+
+void RenderTreeUpdater::pushParent(Element& element, Style::Change changeType)
+{
+    m_parentStack.append(Parent(element, changeType));
+
+    updateBeforeOrAfterPseudoElement(element, BEFORE);
+}
+
+void RenderTreeUpdater::popParent()
+{
+    auto& parent = m_parentStack.last();
+
+    if (parent.element) {
+        updateBeforeOrAfterPseudoElement(*parent.element, AFTER);
+
+        if (parent.element->hasCustomStyleResolveCallbacks() && parent.styleChange == Style::Detach && parent.element->renderer())
+            parent.element->didAttachRenderers();
+    }
+    m_parentStack.removeLast();
+}
+
+void RenderTreeUpdater::popParentsToDepth(unsigned depth)
+{
+    ASSERT(m_parentStack.size() >= depth);
+
+    while (m_parentStack.size() > depth)
+        popParent();
+}
+
+static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
+{
+    const RenderStyle& currentStyle = renderer->style();
+
+    const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
+    if (!pseudoStyleCache)
+        return false;
+
+    for (auto& cache : *pseudoStyleCache) {
+        RefPtr<RenderStyle> newPseudoStyle;
+        PseudoId pseudoId = cache->styleType();
+        if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
+            newPseudoStyle = renderer->uncachedFirstLineStyle(newStyle);
+        else
+            newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
+        if (!newPseudoStyle)
+            return true;
+        if (*newPseudoStyle != *cache) {
+            if (pseudoId < FIRST_INTERNAL_PSEUDOID)
+                newStyle->setHasPseudoStyle(pseudoId);
+            newStyle->addCachedPseudoStyle(newPseudoStyle);
+            if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
+                // FIXME: We should do an actual diff to determine whether a repaint vs. layout
+                // is needed, but for now just assume a layout will be required. The diff code
+                // in RenderObject::setStyle would need to be factored out so that it could be reused.
+                renderer->setNeedsLayoutAndPrefWidthsRecalc();
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::ElementUpdate& update)
+{
+    bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.isNamedFlowContentNode());
+    if (shouldTearDownRenderers)
+        detachRenderTree(element, Style::ReattachDetach);
+
+    bool shouldCreateNewRenderer = !element.renderer() && update.style;
+    if (shouldCreateNewRenderer) {
+        if (element.hasCustomStyleResolveCallbacks())
+            element.willAttachRenderers();
+        createRenderer(element, *update.style);
+        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(element);
+        return;
+    }
+
+    if (!element.renderer())
+        return;
+    auto& renderer = *element.renderer();
+
+    if (update.isSynthetic) {
+        renderer.setStyle(*update.style, StyleDifferenceRecompositeLayer);
+        return;
+    }
+
+    if (update.change == Style::NoChange) {
+        if (pseudoStyleCacheIsInvalid(&renderer, update.style.get()) || (parent().styleChange == Style::Force && renderer.requiresForcedStyleRecalcPropagation())) {
+            renderer.setStyle(*update.style, StyleDifferenceEqual);
+            return;
+        }
+        return;
+    }
+
+    renderer.setStyle(*update.style, StyleDifferenceEqual);
+}
+
+#if ENABLE(CSS_REGIONS)
+static RenderNamedFlowThread* moveToFlowThreadIfNeeded(Element& element, const RenderStyle& style)
+{
+    if (!element.shouldMoveToFlowThread(style))
+        return nullptr;
+
+    FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
+    RenderNamedFlowThread& parentFlowRenderer = flowThreadController.ensureRenderFlowThreadWithName(style.flowThread());
+    flowThreadController.registerNamedFlowContentElement(element, parentFlowRenderer);
+    return &parentFlowRenderer;
+}
+#endif
+
+void RenderTreeUpdater::createRenderer(Element& element, RenderStyle& style)
+{
+    if (!shouldCreateRenderer(element, renderTreePosition().parent()))
+        return;
+
+    RenderNamedFlowThread* parentFlowRenderer = nullptr;
+#if ENABLE(CSS_REGIONS)
+    parentFlowRenderer = moveToFlowThreadIfNeeded(element, style);
+#endif
+
+    if (!element.rendererIsNeeded(style))
+        return;
+
+    renderTreePosition().computeNextSibling(element);
+
+    RenderTreePosition insertionPosition = parentFlowRenderer
+        ? RenderTreePosition(*parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
+        : renderTreePosition();
+
+    RenderElement* newRenderer = element.createElementRenderer(style, insertionPosition).leakPtr();
+    if (!newRenderer)
+        return;
+    if (!insertionPosition.canInsert(*newRenderer)) {
+        newRenderer->destroy();
+        return;
+    }
+
+    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
+    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
+    newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState());
+
+    element.setRenderer(newRenderer);
+
+    Ref<RenderStyle> animatedStyle = newRenderer->style();
+    newRenderer->animation().updateAnimations(*newRenderer, animatedStyle, animatedStyle);
+    newRenderer->setStyleInternal(WTFMove(animatedStyle));
+
+    newRenderer->initializeStyle();
+
+#if ENABLE(FULLSCREEN_API)
+    if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
+        newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), m_document);
+        if (!newRenderer)
+            return;
+    }
+#endif
+    // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
+    insertionPosition.insert(*newRenderer);
+
+    if (AXObjectCache* cache = m_document.axObjectCache())
+        cache->updateCacheAfterNodeIsAttached(&element);
+}
+
+static bool textRendererIsNeeded(const Text& textNode, const RenderTreePosition& renderTreePosition)
+{
+    const RenderElement& parentRenderer = renderTreePosition.parent();
+    if (!parentRenderer.canHaveChildren())
+        return false;
+    if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
+        return false;
+    if (textNode.isEditingText())
+        return true;
+    if (!textNode.length())
+        return false;
+    if (!textNode.containsOnlyWhitespace())
+        return true;
+    // This text node has nothing but white space. We may still need a renderer in some cases.
+    if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
+        return false;
+    if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
+        return true;
+
+    RenderObject* previousRenderer = renderTreePosition.previousSiblingRenderer(textNode);
+    if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
+        return false;
+
+    if (parentRenderer.isRenderInline()) {
+        // <span><div/> <div/></span>
+        if (previousRenderer && !previousRenderer->isInline())
+            return false;
+    } else {
+        if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
+            return false;
+        
+        RenderObject* first = parentRenderer.firstChild();
+        while (first && first->isFloatingOrOutOfFlowPositioned())
+            first = first->nextSibling();
+        RenderObject* nextRenderer = renderTreePosition.nextSiblingRenderer(textNode);
+        if (!first || nextRenderer == first) {
+            // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
+            return false;
+        }
+    }
+    return true;
+}
+
+static void createTextRenderer(Text& textNode, RenderTreePosition& renderTreePosition)
+{
+    ASSERT(!textNode.renderer());
+
+    auto newRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
+    ASSERT(newRenderer);
+
+    renderTreePosition.computeNextSibling(textNode);
+
+    if (!renderTreePosition.canInsert(*newRenderer))
+        return;
+
+    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
+    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
+    newRenderer->setFlowThreadState(renderTreePosition.parent().flowThreadState());
+
+    textNode.setRenderer(newRenderer.get());
+    renderTreePosition.insert(*newRenderer.leakPtr());
+}
+
+void RenderTreeUpdater::updateTextRenderer(Text& text)
+{
+    bool hasRenderer = text.renderer();
+    bool needsRenderer = textRendererIsNeeded(text, renderTreePosition());
+    if (hasRenderer) {
+        if (needsRenderer)
+            return;
+        Style::detachTextRenderer(text);
+        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
+        return;
+    }
+    if (!needsRenderer)
+        return;
+    createTextRenderer(text, renderTreePosition());
+    invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
+}
+
+void RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
+{
+    // FIXME: This needs to traverse in composed tree order.
+
+    // This function finds sibling text renderers where the results of textRendererIsNeeded may have changed as a result of
+    // the current node gaining or losing the renderer. This can only affect white space text nodes.
+    for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
+        if (is<Element>(*sibling)) {
+            if (m_styleUpdate->elementUpdate(downcast<Element>(*sibling)))
+                return;
+            // Text renderers beyond rendered elements can't be affected.
+            if (!sibling->renderer() || RenderTreePosition::isRendererReparented(*sibling->renderer()))
+                continue;
+            return;
+        }
+        if (!is<Text>(*sibling))
+            continue;
+        Text& textSibling = downcast<Text>(*sibling);
+        if (m_styleUpdate->textUpdate(textSibling))
+            return;
+        if (!textSibling.containsOnlyWhitespace())
+            continue;
+        m_invalidatedWhitespaceOnlyTextSiblings.add(&textSibling);
+    }
+}
+
+static bool needsPseudoElement(Element& current, PseudoId pseudoId)
+{
+    if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
+        return false;
+    if (current.isPseudoElement())
+        return false;
+    if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
+        return false;
+    return true;
+}
+
+void RenderTreeUpdater::updateBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
+{
+    PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement();
+
+    auto* renderer = pseudoElement ? pseudoElement->renderer() : nullptr;
+    if (renderer)
+        renderTreePosition().invalidateNextSibling(*renderer);
+
+    bool needsPseudoElement = WebCore::needsPseudoElement(current, pseudoId);
+    if (!needsPseudoElement) {
+        if (pseudoElement) {
+            if (pseudoId == BEFORE)
+                current.clearBeforePseudoElement();
+            else
+                current.clearAfterPseudoElement();
+        }
+        return;
+    }
+
+    Style::ElementUpdate elementUpdate;
+
+    Ref<RenderStyle> newStyle = *current.renderer()->getCachedPseudoStyle(pseudoId, &current.renderer()->style());
+
+    if (renderer && m_document.frame()->animation().updateAnimations(*renderer, newStyle, newStyle))
+        elementUpdate.isSynthetic = true;
+
+    elementUpdate.change = renderer ? Style::determineChange(renderer->style(), newStyle) : Style::Detach;
+    elementUpdate.style = WTFMove(newStyle);
+
+    if (elementUpdate.change == Style::NoChange)
+        return;
+
+    if (!pseudoElement) {
+        auto newPseudoElement = PseudoElement::create(current, pseudoId);
+        pseudoElement = newPseudoElement.ptr();
+        InspectorInstrumentation::pseudoElementCreated(m_document.page(), newPseudoElement);
+        if (pseudoId == BEFORE)
+            current.setBeforePseudoElement(WTFMove(newPseudoElement));
+        else
+            current.setAfterPseudoElement(WTFMove(newPseudoElement));
+    }
+
+    updateElementRenderer(*pseudoElement, elementUpdate);
+
+    if (elementUpdate.change == Style::Detach)
+        pseudoElement->didAttachRenderers();
+    else
+        pseudoElement->didRecalcStyle(elementUpdate.change);
+}
+
+}
diff --git a/Source/WebCore/style/RenderTreeUpdater.h b/Source/WebCore/style/RenderTreeUpdater.h
new file mode 100644 (file)
index 0000000..14eada3
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RenderTreeUpdater_h
+#define RenderTreeUpdater_h
+
+#include "RenderTreePosition.h"
+#include "StyleChange.h"
+#include "StyleUpdate.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Document;
+class Element;
+class Node;
+class RenderStyle;
+class Text;
+
+class RenderTreeUpdater {
+public:
+    RenderTreeUpdater(Document&);
+
+    void commit(std::unique_ptr<const Style::Update>);
+
+private:
+    void updateRenderTree(ContainerNode& root);
+    void updateTextRenderer(Text&);
+    void updateElementRenderer(Element&, const Style::ElementUpdate&);
+    void createRenderer(Element&, RenderStyle&);
+    void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node&);
+    void updateBeforeOrAfterPseudoElement(Element&, PseudoId);
+
+    struct Parent {
+        Element* element { nullptr };
+        Style::Change styleChange { Style::NoChange };
+        Optional<RenderTreePosition> renderTreePosition;
+
+        Parent(ContainerNode& root);
+        Parent(Element&, Style::Change);
+    };
+    Parent& parent() { return m_parentStack.last(); }
+    RenderTreePosition& renderTreePosition();
+
+    void pushParent(Element&, Style::Change);
+    void popParent();
+    void popParentsToDepth(unsigned depth);
+
+    Document& m_document;
+    std::unique_ptr<const Style::Update> m_styleUpdate;
+
+    Vector<Parent> m_parentStack;
+
+    HashSet<Text*> m_invalidatedWhitespaceOnlyTextSiblings;
+};
+
+}
+#endif
index 5bb78e6..993f8a4 100644 (file)
@@ -29,6 +29,7 @@
 #include "Element.h"
 #include "NodeRenderStyle.h"
 #include "RenderStyle.h"
+#include "StyleUpdate.h"
 
 namespace WebCore {
 namespace Style {
@@ -85,7 +86,7 @@ std::unique_ptr<Relations> commitRelationsToRenderStyle(RenderStyle& style, cons
     return remainingRelations;
 }
 
-void commitRelationsToDocument(std::unique_ptr<Relations> relations)
+void commitRelations(std::unique_ptr<Relations> relations, Update& update)
 {
     if (!relations)
         return;
@@ -124,18 +125,20 @@ void commitRelationsToDocument(std::unique_ptr<Relations> relations)
             element.setChildrenAffectedByLastChildRules();
             break;
         case Relation::FirstChild:
-            if (auto* style = element.renderStyle())
+            if (auto* style = update.elementStyle(element))
                 style->setFirstChildState();
             break;
         case Relation::LastChild:
-            if (auto* style = element.renderStyle())
+            if (auto* style = update.elementStyle(element))
                 style->setLastChildState();
             break;
         case Relation::NthChildIndex:
+            if (auto* style = update.elementStyle(element))
+                style->setUnique();
             element.setChildIndex(relation.value);
             break;
         case Relation::Unique:
-            if (auto* style = element.renderStyle())
+            if (auto* style = update.elementStyle(element))
                 style->setUnique();
             break;
         }
index d5950af..31aa5cc 100644 (file)
@@ -35,6 +35,8 @@ class RenderStyle;
 
 namespace Style {
 
+class Update;
+
 struct Relation {
     enum Type {
         AffectedByActive,
@@ -66,7 +68,7 @@ struct Relation {
 using Relations = Vector<Relation, 8>;
 
 std::unique_ptr<Relations> commitRelationsToRenderStyle(RenderStyle&, const Element&, const Relations&);
-void commitRelationsToDocument(std::unique_ptr<Relations>);
+void commitRelations(std::unique_ptr<Relations>, Update&);
 
 }
 }
index 1e8db1e..a91f66a 100644 (file)
@@ -33,6 +33,7 @@
 #include "NodeRenderStyle.h"
 #include "RenderStyle.h"
 #include "SVGElement.h"
+#include "StyleUpdate.h"
 #include "StyledElement.h"
 #include "VisitedLinkState.h"
 #include "WebVTTElement.h"
@@ -44,6 +45,7 @@ namespace Style {
 static const unsigned cStyleSearchThreshold = 10;
 
 struct SharingResolver::Context {
+    const Update& update;
     const StyledElement& element;
     bool elementAffectedByClassRules;
     EInsideLink elementLinkState;
@@ -67,7 +69,7 @@ static inline bool elementHasDirectionAuto(const Element& element)
     return is<HTMLElement>(element) && downcast<HTMLElement>(element).hasDirectionAuto();
 }
 
-RefPtr<RenderStyle> SharingResolver::resolve(const Element& searchElement)
+RefPtr<RenderStyle> SharingResolver::resolve(const Element& searchElement, const Update& update)
 {
     if (!is<StyledElement>(searchElement))
         return nullptr;
@@ -77,7 +79,7 @@ RefPtr<RenderStyle> SharingResolver::resolve(const Element& searchElement)
     auto& parentElement = *element.parentElement();
     if (parentElement.shadowRoot())
         return nullptr;
-    if (!parentElement.renderStyle())
+    if (!update.elementStyle(parentElement))
         return nullptr;
     // If the element has inline style it is probably unique.
     if (element.inlineStyle())
@@ -95,6 +97,7 @@ RefPtr<RenderStyle> SharingResolver::resolve(const Element& searchElement)
         return nullptr;
 
     Context context {
+        update,
         element,
         element.hasClass() && classNamesAffectedByRules(element.classNames()),
         m_document.visitedLinkState().determineLinkState(element)
@@ -127,7 +130,7 @@ RefPtr<RenderStyle> SharingResolver::resolve(const Element& searchElement)
 
     m_elementsSharingStyle.add(&element, shareElement);
 
-    return RenderStyle::clone(shareElement->renderStyle());
+    return RenderStyle::clone(update.elementStyle(*shareElement));
 }
 
 StyledElement* SharingResolver::findSibling(const Context& context, Node* node, unsigned& count) const
@@ -195,7 +198,7 @@ static bool canShareStyleWithControl(const HTMLFormControlElement& element, cons
 bool SharingResolver::canShareStyleWithElement(const Context& context, const StyledElement& candidateElement) const
 {
     auto& element = context.element;
-    auto* style = candidateElement.renderStyle();
+    auto* style = context.update.elementStyle(candidateElement);
     if (!style)
         return false;
     if (style->unique())
index d2754e2..5f9505b 100644 (file)
@@ -42,11 +42,13 @@ class StyledElement;
 
 namespace Style {
 
+class Update;
+
 class SharingResolver {
 public:
     SharingResolver(const Document&, const DocumentRuleSets&, const SelectorFilter&);
 
-    RefPtr<RenderStyle> resolve(const Element&);
+    RefPtr<RenderStyle> resolve(const Element&, const Update&);
 
 private:
     struct Context;
index a7070e6..c53655b 100644 (file)
@@ -4,7 +4,7 @@
  *           (C) 2001 Peter Kelly (pmk@post.com)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2007 David Smith (catfish.man@gmail.com)
- * Copyright (C) 2004-2010, 2012-2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2010, 2012-2016 Apple Inc. All rights reserved.
  *           (C) 2007 Eric Seidel (eric@webkit.org)
  *
  * This library is free software; you can redistribute it and/or
 #include "config.h"
 #include "StyleTreeResolver.h"
 
-#include "AXObjectCache.h"
-#include "AnimationController.h"
 #include "AuthorStyleSheets.h"
 #include "CSSFontSelector.h"
 #include "ComposedTreeAncestorIterator.h"
 #include "ComposedTreeIterator.h"
 #include "ElementIterator.h"
-#include "ElementRareData.h"
-#include "FlowThreadController.h"
+#include "HTMLBodyElement.h"
 #include "HTMLSlotElement.h"
-#include "InspectorInstrumentation.h"
 #include "LoaderStrategy.h"
 #include "MainFrame.h"
 #include "NodeRenderStyle.h"
-#include "NodeTraversal.h"
 #include "PlatformStrategies.h"
-#include "RenderFullScreen.h"
-#include "RenderNamedFlowThread.h"
-#include "RenderText.h"
-#include "RenderTreePosition.h"
-#include "RenderWidget.h"
 #include "Settings.h"
 #include "ShadowRoot.h"
 #include "StyleResolver.h"
@@ -60,10 +50,7 @@ namespace WebCore {
 
 namespace Style {
 
-enum DetachType { NormalDetach, ReattachDetach };
-
 static void attachTextRenderer(Text&, RenderTreePosition&);
-static void detachRenderTree(Element&, DetachType);
 static void resolveTextNode(Text&, RenderTreePosition&);
 
 class SelectorFilterPusher {
@@ -114,6 +101,10 @@ TreeResolver::TreeResolver(Document& document)
     ensurePlaceholderStyle(document);
 }
 
+TreeResolver::~TreeResolver()
+{
+}
+
 TreeResolver::Scope::Scope(Document& document)
     : styleResolver(document.ensureStyleResolver())
     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
@@ -131,16 +122,14 @@ TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
 TreeResolver::Parent::Parent(Document& document, Change change)
     : element(nullptr)
     , style(*document.renderStyle())
-    , renderTreePosition(*document.renderView())
     , change(change)
 {
 }
 
-TreeResolver::Parent::Parent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
+TreeResolver::Parent::Parent(Element& element, ElementUpdate& update)
     : element(&element)
-    , style(style)
-    , renderTreePosition(renderTreePosition)
-    , change(change)
+    , style(*update.style)
+    , change(update.change)
 {
 }
 
@@ -160,17 +149,6 @@ void TreeResolver::popScope()
     return m_scopeStack.removeLast();
 }
 
-static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
-{
-    if (!element.document().shouldCreateRenderers())
-        return false;
-    if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
-        return false;
-    if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
-        return false;
-    return true;
-}
-
 Ref<RenderStyle> TreeResolver::styleForElement(Element& element, RenderStyle& inheritedStyle)
 {
     if (!m_document.haveStylesheetsLoaded() && !element.renderer()) {
@@ -178,87 +156,27 @@ Ref<RenderStyle> TreeResolver::styleForElement(Element& element, RenderStyle& in
         return *placeholderStyle;
     }
 
+    scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
+
     if (element.hasCustomStyleResolveCallbacks()) {
-        RenderStyle* shadowHostStyle = scope().shadowRoot ? scope().shadowRoot->host()->renderStyle() : nullptr;
+        RenderStyle* shadowHostStyle = scope().shadowRoot ? m_update->elementStyle(*scope().shadowRoot->host()) : nullptr;
         if (auto customStyle = element.resolveCustomStyle(inheritedStyle, shadowHostStyle)) {
-            Style::commitRelationsToDocument(WTFMove(customStyle->relations));
+            if (customStyle->relations)
+                commitRelations(WTFMove(customStyle->relations), *m_update);
+
             return WTFMove(customStyle->renderStyle);
         }
     }
 
-    if (auto style = scope().sharingResolver.resolve(element))
+    if (auto style = scope().sharingResolver.resolve(element, *m_update))
         return *style;
 
     auto elementStyle = scope().styleResolver.styleForElement(element, &inheritedStyle, MatchAllRules, nullptr, &scope().selectorFilter);
 
-    Style::commitRelationsToDocument(WTFMove(elementStyle.relations));
-    return WTFMove(elementStyle.renderStyle);
-}
-
-#if ENABLE(CSS_REGIONS)
-static RenderNamedFlowThread* moveToFlowThreadIfNeeded(Element& element, const RenderStyle& style)
-{
-    if (!element.shouldMoveToFlowThread(style))
-        return 0;
-
-    FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
-    RenderNamedFlowThread& parentFlowRenderer = flowThreadController.ensureRenderFlowThreadWithName(style.flowThread());
-    flowThreadController.registerNamedFlowContentElement(element, parentFlowRenderer);
-    return &parentFlowRenderer;
-}
-#endif
-
-void TreeResolver::createRenderer(Element& element, RenderTreePosition& renderTreePosition, RefPtr<RenderStyle>&& resolvedStyle)
-{
-    ASSERT(shouldCreateRenderer(element, renderTreePosition.parent()));
-    ASSERT(resolvedStyle);
+    if (elementStyle.relations)
+        commitRelations(WTFMove(elementStyle.relations), *m_update);
 
-    RenderNamedFlowThread* parentFlowRenderer = 0;
-#if ENABLE(CSS_REGIONS)
-    parentFlowRenderer = moveToFlowThreadIfNeeded(element, *resolvedStyle);
-#endif
-
-    if (!element.rendererIsNeeded(*resolvedStyle))
-        return;
-
-    renderTreePosition.computeNextSibling(element);
-
-    RenderTreePosition insertionPosition = parentFlowRenderer
-        ? RenderTreePosition(*parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
-        : renderTreePosition;
-
-    RenderElement* newRenderer = element.createElementRenderer(resolvedStyle.releaseNonNull(), insertionPosition).leakPtr();
-    if (!newRenderer)
-        return;
-    if (!insertionPosition.canInsert(*newRenderer)) {
-        newRenderer->destroy();
-        return;
-    }
-
-    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
-    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
-    newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState());
-
-    // Code below updateAnimations() can depend on Element::renderer() already being set.
-    element.setRenderer(newRenderer);
-
-    // FIXME: There's probably a better way to factor this.
-    // This just does what setAnimatedStyle() does, except with setStyleInternal() instead of setStyle().
-    Ref<RenderStyle> animatedStyle = newRenderer->style();
-    newRenderer->animation().updateAnimations(*newRenderer, animatedStyle, animatedStyle);
-    newRenderer->setStyleInternal(WTFMove(animatedStyle));
-
-    newRenderer->initializeStyle();
-
-#if ENABLE(FULLSCREEN_API)
-    if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
-        newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), m_document);
-        if (!newRenderer)
-            return;
-    }
-#endif
-    // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
-    insertionPosition.insert(*newRenderer);
+    return WTFMove(elementStyle.renderStyle);
 }
 
 static void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
@@ -348,7 +266,6 @@ static void createTextRendererIfNeeded(Text& textNode, RenderTreePosition& rende
     newRenderer->setFlowThreadState(renderTreePosition.parent().flowThreadState());
 
     textNode.setRenderer(newRenderer.get());
-    // Parent takes care of the animations, no need to call setAnimatableStyle.
     renderTreePosition.insert(*newRenderer.leakPtr());
 }
 
@@ -381,75 +298,11 @@ void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfRepla
         textNode.renderer()->setTextWithOffset(textNode.data(), offsetOfReplacedData, lengthOfReplacedData);
 }
 
-void TreeResolver::createRenderTreeForChildren(ContainerNode& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
-{
-    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-        ASSERT((!child->renderer() || child->isNamedFlowContentNode()) || current.shadowRoot());
-        if (child->renderer()) {
-            renderTreePosition.invalidateNextSibling(*child->renderer());
-            continue;
-        }
-        if (is<Text>(*child)) {
-            attachTextRenderer(downcast<Text>(*child), renderTreePosition);
-            continue;
-        }
-        if (is<Element>(*child))
-            createRenderTreeRecursively(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
-    }
-}
-
-void TreeResolver::createRenderTreeForShadowRoot(ShadowRoot& shadowRoot)
-{
-    ASSERT(shadowRoot.host());
-    ASSERT(shadowRoot.host()->renderer());
-
-    pushScope(shadowRoot);
-
-    auto& renderer = *shadowRoot.host()->renderer();
-    RenderTreePosition renderTreePosition(renderer);
-    createRenderTreeForChildren(shadowRoot, renderer.style(), renderTreePosition);
-
-    popScope();
-
-    shadowRoot.clearNeedsStyleRecalc();
-    shadowRoot.clearChildNeedsStyleRecalc();
-}
-
-static PseudoElement* beforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
-{
-    ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
-    if (pseudoId == BEFORE)
-        return current.beforePseudoElement();
-    return current.afterPseudoElement();
-}
-
-static void setBeforeOrAfterPseudoElement(Element& current, Ref<PseudoElement>&& pseudoElement, PseudoId pseudoId)
-{
-    ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
-    if (pseudoId == BEFORE) {
-        current.setBeforePseudoElement(WTFMove(pseudoElement));
-        return;
-    }
-    current.setAfterPseudoElement(WTFMove(pseudoElement));
-}
-
-static void clearBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
-{
-    ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
-    if (pseudoId == BEFORE) {
-        current.clearBeforePseudoElement();
-        return;
-    }
-    current.clearAfterPseudoElement();
-}
-
 static void resetStyleForNonRenderedDescendants(Element& current)
 {
     // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
-    ASSERT(!current.renderer());
     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
     for (auto& child : childrenOfType<Element>(current)) {
-        ASSERT(!child.renderer());
         bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
         if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
@@ -466,111 +319,6 @@ static void resetStyleForNonRenderedDescendants(Element& current)
     }
 }
 
-static bool needsPseudoElement(Element& current, PseudoId pseudoId)
-{
-    if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
-        return false;
-    if (current.isPseudoElement())
-        return false;
-    if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
-        return false;
-    return true;
-}
-
-void TreeResolver::createRenderTreeForBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
-{
-    if (!needsPseudoElement(current, pseudoId))
-        return;
-    Ref<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId);
-    InspectorInstrumentation::pseudoElementCreated(m_document.page(), pseudoElement.get());
-    setBeforeOrAfterPseudoElement(current, pseudoElement.copyRef(), pseudoId);
-    createRenderTreeRecursively(pseudoElement.get(), *current.renderStyle(), renderTreePosition, nullptr);
-}
-
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-void TreeResolver::createRenderTreeForSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
-{
-    ASSERT(shouldCreateRenderer(slot, renderTreePosition.parent()));
-
-    if (auto* assignedNodes = slot.assignedNodes()) {
-        pushEnclosingScope();
-        for (auto* child : *assignedNodes) {
-            if (is<Text>(*child))
-                attachTextRenderer(downcast<Text>(*child), renderTreePosition);
-            else if (is<Element>(*child))
-                createRenderTreeRecursively(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
-        }
-        popScope();
-    } else {
-        SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, slot);
-        createRenderTreeForChildren(slot, inheritedStyle, renderTreePosition);
-    }
-
-    slot.clearNeedsStyleRecalc();
-    slot.clearChildNeedsStyleRecalc();
-}
-#endif
-
-void TreeResolver::createRenderTreeRecursively(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, RefPtr<RenderStyle>&& resolvedStyle)
-{
-    ASSERT(!current.renderer());
-
-    PostResolutionCallbackDisabler callbackDisabler(m_document);
-    WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
-
-    bool shouldCallCreateRenderer = shouldCreateRenderer(current, renderTreePosition.parent());
-
-    RefPtr<RenderStyle> style = resolvedStyle;
-    if (!style)
-        style = styleForElement(current, inheritedStyle);
-
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is<HTMLSlotElement>(current)) {
-        if (shouldCallCreateRenderer && current.rendererIsNeeded(*style))
-            createRenderTreeForSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition);
-        return;
-    }
-#endif
-
-    if (current.hasCustomStyleResolveCallbacks())
-        current.willAttachRenderers();
-
-    if (shouldCallCreateRenderer)
-        createRenderer(current, renderTreePosition, style.releaseNonNull());
-
-    if (auto* renderer = current.renderer()) {
-        SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
-
-        RenderTreePosition childRenderTreePosition(*renderer);
-        createRenderTreeForBeforeOrAfterPseudoElement(current, BEFORE, childRenderTreePosition);
-
-        auto* shadowRoot = current.shadowRoot();
-        if (shadowRoot) {
-            selectorFilterPusher.push();
-            createRenderTreeForShadowRoot(*shadowRoot);
-        } else if (current.firstChild())
-            selectorFilterPusher.push();
-
-        bool skipChildren = shadowRoot;
-        if (!skipChildren)
-            createRenderTreeForChildren(current, renderer->style(), childRenderTreePosition);
-
-        if (AXObjectCache* cache = m_document.axObjectCache())
-            cache->updateCacheAfterNodeIsAttached(&current);
-
-        createRenderTreeForBeforeOrAfterPseudoElement(current, AFTER, childRenderTreePosition);
-
-        current.updateFocusAppearanceAfterAttachIfNeeded();
-    } else
-        resetStyleForNonRenderedDescendants(current);
-
-    current.clearNeedsStyleRecalc();
-    current.clearChildNeedsStyleRecalc();
-
-    if (current.hasCustomStyleResolveCallbacks())
-        current.didAttachRenderers();
-}
-
 static void detachChildren(ContainerNode& current, DetachType detachType)
 {
     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
@@ -606,7 +354,7 @@ static void detachSlotAssignees(HTMLSlotElement& slot, DetachType detachType)
 }
 #endif
 
-static void detachRenderTree(Element& current, DetachType detachType)
+void detachRenderTree(Element& current, DetachType detachType)
 {
     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
 
@@ -637,79 +385,49 @@ static void detachRenderTree(Element& current, DetachType detachType)
         current.didDetachRenderers();
 }
 
-static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
+ElementUpdate TreeResolver::resolveElement(Element& element)
 {
-    const RenderStyle& currentStyle = renderer->style();
+    auto newStyle = styleForElement(element, parent().style);
 
-    const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
-    if (!pseudoStyleCache)
-        return false;
+    auto* renderer = element.renderer();
 
-    for (auto& cache : *pseudoStyleCache) {
-        RefPtr<RenderStyle> newPseudoStyle;
-        PseudoId pseudoId = cache->styleType();
-        if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
-            newPseudoStyle = renderer->uncachedFirstLineStyle(newStyle);
-        else
-            newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
-        if (!newPseudoStyle)
-            return true;
-        if (*newPseudoStyle != *cache) {
-            if (pseudoId < FIRST_INTERNAL_PSEUDOID)
-                newStyle->setHasPseudoStyle(pseudoId);
-            newStyle->addCachedPseudoStyle(newPseudoStyle);
-            if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
-                // FIXME: We should do an actual diff to determine whether a repaint vs. layout
-                // is needed, but for now just assume a layout will be required. The diff code
-                // in RenderObject::setStyle would need to be factored out so that it could be reused.
-                renderer->setNeedsLayoutAndPrefWidthsRecalc();
-            }
-            return true;
-        }
-    }
-    return false;
-}
+    bool affectsRenderedSubtree = renderer || newStyle->display() != NONE || element.rendererIsNeeded(newStyle) || element.shouldMoveToFlowThread(newStyle);
+    if (!affectsRenderedSubtree)
+        return { };
 
-Change TreeResolver::resolveElement(Element& current)
-{
-    Change localChange = Detach;
-    RefPtr<RenderStyle> newStyle;
-    RefPtr<RenderStyle> currentStyle = current.renderStyle();
-
-    if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
-        Ref<RenderStyle> style(styleForElement(current, parent().style));
-        newStyle = style.ptr();
-        localChange = determineChange(*currentStyle, style);
-    }
-    if (localChange == Detach) {
-        if (current.renderer() || current.isNamedFlowContentNode())
-            detachRenderTree(current, ReattachDetach);
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-        else if (is<HTMLSlotElement>(current))
-            detachRenderTree(current, ReattachDetach);
-#endif
-        createRenderTreeRecursively(current, parent().style, parent().renderTreePosition, newStyle.release());
-        invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
+    ElementUpdate update;
 
-        return Detach;
-    }
+    bool needsNewRenderer = !renderer || element.styleChangeType() == ReconstructRenderTree || parent().change == Detach;
+    if (!needsNewRenderer && m_document.frame()->animation().updateAnimations(*renderer, newStyle, newStyle))
+        update.isSynthetic = true;
 
-    if (RenderElement* renderer = current.renderer()) {
-        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (parent().change == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
-            renderer->setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
-    }
+    update.change = needsNewRenderer ? Detach : determineChange(renderer->style(), newStyle);
+    update.style = WTFMove(newStyle);
+
+    if (element.styleChangeType() == SyntheticStyleChange)
+        update.isSynthetic = true;
 
-    // If "rem" units are used anywhere in the document, and if the document element's font size changes, then force font updating
-    // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
-    if (m_document.authorStyleSheets().usesRemUnits() && m_document.documentElement() == &current && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
-        // Cached RenderStyles may depend on the re units.
-        scope().styleResolver.invalidateMatchedPropertiesCache();
-        return Force;
+    if (&element == m_document.documentElement()) {
+        m_documentElementStyle = update.style;
+
+        // If "rem" units are used anywhere in the document, and if the document element's font size changes, then force font updating
+        // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
+        if (m_document.authorStyleSheets().usesRemUnits() && update.change != NoChange && renderer && renderer->style().fontSize() != update.style->fontSize()) {
+            // Cached RenderStyles may depend on the rem units.
+            scope().styleResolver.invalidateMatchedPropertiesCache();
+            update.change = Force;
+        }
     }
-    if (parent().change == Force || current.styleChangeType() >= FullStyleChange)
-        return Force;
 
-    return localChange;
+    // This is needed for resolving color:-webkit-text for subsequent elements.
+    // FIXME: We shouldn't mutate document when resolving style.
+    if (&element == m_document.body())
+        m_document.setTextColor(update.style->visitedDependentColor(CSSPropertyColor));
+
+    if (update.change != Detach && (parent().change == Force || element.styleChangeType() >= FullStyleChange))
+        update.change = Force;
+
+    return update;
 }
 
 void resolveTextNode(Text& text, RenderTreePosition& renderTreePosition)
@@ -731,30 +449,6 @@ void resolveTextNode(Text& text, RenderTreePosition& renderTreePosition)
     invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
 }
 
-void TreeResolver::resolveBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
-{
-    if (!current.renderer())
-        return;
-    PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId);
-    if (!existingPseudoElement) {
-        createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
-        return;
-    }
-
-    if (existingPseudoElement->renderer())
-        renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
-
-    if (change == NoChange && !existingPseudoElement->needsStyleRecalc())
-        return;
-
-    if (needsPseudoElement(current, pseudoId)) {
-        auto change = resolveElement(*existingPseudoElement);
-        existingPseudoElement->didRecalcStyle(change);
-        existingPseudoElement->clearNeedsStyleRecalc();
-    } else
-        clearBeforeOrAfterPseudoElement(current, pseudoId);
-}
-
 #if PLATFORM(IOS)
 static EVisibility elementImplicitVisibility(const Element* element)
 {
@@ -809,11 +503,11 @@ private:
 };
 #endif // PLATFORM(IOS)
 
-void TreeResolver::pushParent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
+void TreeResolver::pushParent(Element& element, ElementUpdate& update)
 {
     scope().selectorFilter.pushParent(&element);
 
-    Parent parent(element, style, renderTreePosition, change);
+    Parent parent(element, update);
 
     if (auto* shadowRoot = element.shadowRoot()) {
         pushScope(*shadowRoot);
@@ -827,16 +521,12 @@ void TreeResolver::pushParent(Element& element, RenderStyle& style, RenderTreePo
 #endif
 
     m_parentStack.append(WTFMove(parent));
-
-    resolveBeforeOrAfterPseudoElement(element, change, BEFORE, renderTreePosition);
 }
 
 void TreeResolver::popParent()
 {
     auto& parentElement = *parent().element;
 
-    resolveBeforeOrAfterPseudoElement(parentElement, parent().change, AFTER, parent().renderTreePosition);
-
     parentElement.clearNeedsStyleRecalc();
     parentElement.clearChildNeedsStyleRecalc();
 
@@ -857,6 +547,15 @@ void TreeResolver::popParentsToDepth(unsigned depth)
         popParent();
 }
 
+static bool shouldResolvePseudoElement(PseudoElement* pseudoElement)
+{
+    if (!pseudoElement)
+        return false;
+    bool needsStyleRecalc = pseudoElement->needsStyleRecalc();
+    pseudoElement->clearNeedsStyleRecalc();
+    return needsStyleRecalc;
+}
+
 void TreeResolver::resolveComposedTree()
 {
     ASSERT(m_parentStack.size() == 1);
@@ -878,12 +577,12 @@ void TreeResolver::resolveComposedTree()
         ASSERT(node.containingShadowRoot() == scope().shadowRoot);
         ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
 
-        if (auto* existingRenderer = node.renderer())
-            parent.renderTreePosition.invalidateNextSibling(*existingRenderer);
-
         if (is<Text>(node)) {
-            if (node.needsStyleRecalc())
-                resolveTextNode(downcast<Text>(node), parent.renderTreePosition);
+            auto& text = downcast<Text>(node);
+            if (text.styleChangeType() == ReconstructRenderTree && parent.change != Detach)
+                m_update->addText(text, parent.element);
+
+            text.clearNeedsStyleRecalc();
             it.traverseNextSkippingChildren();
             continue;
         }
@@ -895,9 +594,12 @@ void TreeResolver::resolveComposedTree()
         if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
             parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
 
-        Change change = NoChange;
+        bool shouldResolveForPseudoElement = shouldResolvePseudoElement(element.beforePseudoElement()) || shouldResolvePseudoElement(element.afterPseudoElement());
+
+        ElementUpdate update;
+        update.style = element.renderStyle();
 
-        bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || affectedByPreviousSibling;
+        bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || shouldResolveForPseudoElement || affectedByPreviousSibling;
         if (shouldResolve) {
 #if PLATFORM(IOS)
             CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&element, element.renderStyle());
@@ -910,45 +612,48 @@ void TreeResolver::resolveComposedTree()
                     continue;
                 }
             }
-            change = resolveElement(element);
 
-            element.clearNeedsStyleRecalc();
+            update = resolveElement(element);
 
             if (element.hasCustomStyleResolveCallbacks())
-                element.didRecalcStyle(change);
+                element.didRecalcStyle(update.change);
 
-            if (change == Detach) {
-                it.traverseNextSkippingChildren();
-                continue;
-            }
+            if (affectedByPreviousSibling && update.change != Detach)
+                update.change = Force;
 
-            if (affectedByPreviousSibling)
-                change = Force;
+            if (update.style)
+                m_update->addElement(element, parent.element, update);
+
+            element.clearNeedsStyleRecalc();
         }
 
+
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
         if (is<HTMLSlotElement>(element)) {
             // FIXME: We should compute style for the slot and use it as parent style.
-            // FIXME: This should be display:contents check.
-            // Duplicate the style and render tree position from the current context.
-            pushParent(element, parent.style.get(), parent.renderTreePosition, change);
+            // Duplicate the style from the parent context.
+            ElementUpdate slotUpdate;
+            slotUpdate.style = parent.style.ptr();
+            slotUpdate.change = update.change;
+            if (!shouldResolve)
+                m_update->addElement(element, parent.element, update);
+            pushParent(element, slotUpdate);
             it.traverseNext();
             continue;
         }
 #endif
-        auto* renderer = element.renderer();
-        if (!renderer) {
+        if (!update.style) {
             resetStyleForNonRenderedDescendants(element);
             element.clearChildNeedsStyleRecalc();
         }
 
-        bool shouldIterateChildren = renderer && (element.childNeedsStyleRecalc() || change != NoChange);
+        bool shouldIterateChildren = update.style && (element.childNeedsStyleRecalc() || update.change != NoChange);
         if (!shouldIterateChildren) {
             it.traverseNextSkippingChildren();
             continue;
         }
 
-        pushParent(element, renderer->style(), RenderTreePosition(*renderer), change);
+        pushParent(element, update);
 
         it.traverseNext();
     }
@@ -956,24 +661,24 @@ void TreeResolver::resolveComposedTree()
     popParentsToDepth(1);
 }
 
-void TreeResolver::resolve(Change change)
+std::unique_ptr<const Update> TreeResolver::resolve(Change change)
 {
     auto& renderView = *m_document.renderView();
 
     Element* documentElement = m_document.documentElement();
     if (!documentElement)
-        return;
+        return nullptr;
     if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
-        return;
+        return nullptr;
 
+    m_update = std::make_unique<Update>(m_document);
     m_scopeStack.append(adoptRef(*new Scope(m_document)));
+    m_parentStack.append(Parent(m_document, change));
 
     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
 
-    m_parentStack.append(Parent(m_document, change));
-
     resolveComposedTree();
 
     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
@@ -981,11 +686,11 @@ void TreeResolver::resolve(Change change)
 
     m_parentStack.clear();
     m_scopeStack.clear();
-}
 
-void detachRenderTree(Element& element)
-{
-    detachRenderTree(element, NormalDetach);
+    if (m_update->roots().isEmpty())
+        return { };
+
+    return WTFMove(m_update);
 }
 
 static Vector<std::function<void ()>>& postResolutionCallbackQueue()
index 0132bf7..93d2226 100644 (file)
@@ -32,7 +32,9 @@
 #include "SelectorFilter.h"
 #include "StyleChange.h"
 #include "StyleSharingResolver.h"
+#include "StyleUpdate.h"
 #include <functional>
+#include <wtf/HashMap.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
@@ -47,32 +49,22 @@ class Settings;
 class ShadowRoot;
 class StyleResolver;
 class Text;
+class TreeChange;
 
 namespace Style {
 
 class TreeResolver {
 public:
     TreeResolver(Document&);
+    ~TreeResolver();
 
-    void resolve(Change);
+    std::unique_ptr<const Update> resolve(Change);
 
 private:
     Ref<RenderStyle> styleForElement(Element&, RenderStyle& inheritedStyle);
 
     void resolveComposedTree();
-    Change resolveElement(Element&);
-    void resolveBeforeOrAfterPseudoElement(Element&, Change, PseudoId, RenderTreePosition&);
-
-
-    void createRenderTreeRecursively(Element&, RenderStyle&, RenderTreePosition&, RefPtr<RenderStyle>&& resolvedStyle);
-    void createRenderer(Element&, RenderTreePosition&, RefPtr<RenderStyle>&& resolvedStyle);
-    void createRenderTreeForBeforeOrAfterPseudoElement(Element&, PseudoId, RenderTreePosition&);
-    void createRenderTreeForChildren(ContainerNode&, RenderStyle&, RenderTreePosition&);
-    void createRenderTreeForShadowRoot(ShadowRoot&);
-
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    void createRenderTreeForSlotAssignees(HTMLSlotElement&, RenderStyle& inheritedStyle, RenderTreePosition&);
-#endif
+    ElementUpdate resolveElement(Element&);
 
     struct Scope : RefCounted<Scope> {
         StyleResolver& styleResolver;
@@ -88,13 +80,12 @@ private:
     struct Parent {
         Element* element;
         Ref<RenderStyle> style;
-        RenderTreePosition renderTreePosition;
         Change change;
         bool didPushScope { false };
         bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle { false };
 
         Parent(Document&, Change);
-        Parent(Element&, RenderStyle&, RenderTreePosition, Change);
+        Parent(Element&, ElementUpdate&);
     };
 
     Scope& scope() { return m_scopeStack.last(); }
@@ -104,16 +95,21 @@ private:
     void pushEnclosingScope();
     void popScope();
 
-    void pushParent(Element&, RenderStyle&, RenderTreePosition, Change);
+    void pushParent(Element&, ElementUpdate&);
     void popParent();
     void popParentsToDepth(unsigned depth);
 
     Document& m_document;
+    RefPtr<RenderStyle> m_documentElementStyle;
+
     Vector<Ref<Scope>, 4> m_scopeStack;
     Vector<Parent, 32> m_parentStack;
+
+    std::unique_ptr<Update> m_update;
 };
 
-void detachRenderTree(Element&);
+enum DetachType { NormalDetach, ReattachDetach };
+void detachRenderTree(Element&, DetachType = NormalDetach);
 void detachTextRenderer(Text&);
 
 void updateTextRendererAfterContentChange(Text&, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData);
diff --git a/Source/WebCore/style/StyleUpdate.cpp b/Source/WebCore/style/StyleUpdate.cpp
new file mode 100644 (file)
index 0000000..31821f9
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StyleUpdate.h"
+
+#include "ComposedTreeAncestorIterator.h"
+#include "Document.h"
+#include "Element.h"
+#include "NodeRenderStyle.h"
+#include "Text.h"
+
+namespace WebCore {
+namespace Style {
+
+Update::Update(Document& document)
+    : m_document(document)
+{
+}
+
+const ElementUpdate* Update::elementUpdate(const Element& element) const
+{
+    auto it = m_elements.find(&element);
+    if (it == m_elements.end())
+        return nullptr;
+    return &it->value;
+}
+
+bool Update::textUpdate(const Text& text) const
+{
+    return m_texts.contains(&text);
+}
+
+RenderStyle* Update::elementStyle(const Element& element) const
+{
+    if (auto* update = elementUpdate(element))
+        return update->style.get();
+    return element.renderStyle();
+}
+
+void Update::addElement(Element& element, Element* parent, ElementUpdate& change)
+{
+    ASSERT(!m_elements.contains(&element));
+    ASSERT(!parent || composedTreeAncestors(element).first() == parent);
+
+    addPossibleRoot(parent);
+    m_elements.add(&element, change);
+}
+
+void Update::addText(Text& text, Element* parent)
+{
+    ASSERT(!m_texts.contains(&text));
+    ASSERT(!parent || composedTreeAncestors(text).first() == parent);
+
+    addPossibleRoot(parent);
+    m_texts.add(&text);
+}
+
+void Update::addPossibleRoot(Element* element)
+{
+    if (!element) {
+        m_roots.add(&m_document);
+        return;
+    }
+    if (m_elements.contains(element))
+        return;
+    m_roots.add(element);
+}
+
+}
+}
diff --git a/Source/WebCore/style/StyleUpdate.h b/Source/WebCore/style/StyleUpdate.h
new file mode 100644 (file)
index 0000000..19377b6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StyleUpdate_h
+#define StyleUpdate_h
+
+#include "Node.h"
+#include "StyleChange.h"
+#include "StyleRelations.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class ContainerNode;
+class Document;
+class Element;
+class Node;
+class RenderStyle;
+class Text;
+
+namespace Style {
+
+struct ElementUpdate {
+    RefPtr<RenderStyle> style;
+    Change change { NoChange };
+    bool isSynthetic { false };
+};
+
+class Update {
+public:
+    Update(Document&);
+
+    const ListHashSet<ContainerNode*>& roots() const { return m_roots; }
+
+    const ElementUpdate* elementUpdate(const Element&) const;
+    bool textUpdate(const Text&) const;
+
+    RenderStyle* elementStyle(const Element&) const;
+
+    const Document& document() const { return m_document; }
+
+    void addElement(Element&, Element* parent, ElementUpdate&);
+    void addText(Text&, Element* parent);
+
+private:
+    void addPossibleRoot(Element*);
+
+    Document& m_document;
+    ListHashSet<ContainerNode*> m_roots;
+    HashMap<const Element*, ElementUpdate> m_elements;
+    HashSet<const Text*> m_texts;
+};
+
+}
+}
+#endif
index 08d3abf..ce8ef74 100644 (file)
@@ -183,11 +183,12 @@ protected:
     void updateRelativeLengthsInformation() { updateRelativeLengthsInformation(selfHasRelativeLengths(), this); }
     void updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement*);
 
+    bool willRecalcStyle(Style::Change) override;
+
     class InstanceInvalidationGuard;
 
 private:
     RenderStyle* computedStyle(PseudoId = NOPSEUDO) final;
-    bool willRecalcStyle(Style::Change) override;
 
     virtual bool isSupported(StringImpl* feature, StringImpl* version) const;
 
index 99142f8..057eeac 100644 (file)
@@ -178,11 +178,12 @@ void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
     SVGGraphicsElement::svgAttributeChanged(attrName);
 }
 
-void SVGUseElement::willAttachRenderers()
+bool SVGUseElement::willRecalcStyle(Style::Change change)
 {
+    // FIXME: Shadow tree should be updated before style recalc.
     if (m_shadowTreeNeedsUpdate)
         updateShadowTree();
-    SVGGraphicsElement::willAttachRenderers();
+    return SVGGraphicsElement::willRecalcStyle(change);
 }
 
 static HashSet<AtomicString> createAllowedElementSet()
index b7c887b..483bf06 100644 (file)
@@ -63,7 +63,7 @@ private:
     void buildPendingResource() override;
     void parseAttribute(const QualifiedName&, const AtomicString&) override;
     void svgAttributeChanged(const QualifiedName&) override;
-    void willAttachRenderers() override;
+    bool willRecalcStyle(Style::Change) override;
     RenderPtr<RenderElement> createElementRenderer(Ref<RenderStyle>&&, const RenderTreePosition&) override;
     void toClipPath(Path&) override;
     bool haveLoadedRequiredResources() override;