WebCore:
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 May 2008 08:05:12 +0000 (08:05 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 May 2008 08:05:12 +0000 (08:05 +0000)
2008-05-29  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Dave Hyatt.

        - speed up DHTML using lazy style resolution and rendere creation

        This change introduces the concept of "lazy attach" - when a node
        is lazy attached, then instead of resolving style and creating a
        renderer right away, we just mark it as needing a style recalc.

        The patch makes use of this mechanism when inserting nodes directly
        using DOM APIs from script. For now this is only done for the
        JavaScript language binding but could also be done for other
        bindings in the future.

        Lazy attach helps some common DHTML patterns - when a node is
        added to the DOM, and then subsequently changed in a
        style-affecting way, this causes an extra style recalc. This is a
        fairly common pattern so it is better to be lazy.

        * bindings/js/JSNodeCustom.cpp:
        (WebCore::JSNode::insertBefore): Request lazy attach.
        (WebCore::JSNode::replaceChild): ditto
        (WebCore::JSNode::appendChild): ditto
        * dom/ContainerNode.cpp:
        (WebCore::ContainerNode::insertBefore): Support lazy attach.
        (WebCore::ContainerNode::replaceChild): ditto
        (WebCore::ContainerNode::appendChild): ditto
        (WebCore::ContainerNode::detach): Clear "changed child" bit if still set.
        * dom/ContainerNode.h:
        * dom/Element.cpp:
        (WebCore::Element::recalcStyle): Adjusted to properly reattach a
        lazy-attached node.
        * dom/Node.cpp:
        (WebCore::Node::insertBefore): Extra parameter for lazy attach
        (still doesn't do anything).
        (WebCore::Node::replaceChild): ditto
        (WebCore::Node::appendChild): ditto
        (WebCore::Node::setChanged): Unrelated but obvious optimization -
        stop marking ancestor as having a changed child once we already reach
        an ancestor so marked.
        (WebCore::outermostLazyAttachedAncestor): Helper function for lazyAttach.
        (WebCore::Node::lazyAttach): Implement lazy attach.
        (WebCore::Node::canLazyAttach): Virtual method - true for most nodes.
        * dom/Node.h:
        * dom/Text.cpp:
        (WebCore::Text::recalcStyle): Properly handle the case of a reattached node.
        * html/HTMLEmbedElement.h:
        (WebCore::HTMLEmbedElement::canLazyAttach): Refuse lazy attach, since
        plugins and frames do important work at rederer creation time.
        * html/HTMLFrameElementBase.h:
        (WebCore::HTMLFrameElementBase::canLazyAttach): Refuse lazy attach, since
        plugins and frames do important work at rederer creation time.
        * html/HTMLFrameSetElement.cpp:
        (WebCore::HTMLFrameSetElement::recalcStyle): Change order so that
        reattach works properly.
        * html/HTMLObjectElement.h:
        (WebCore::HTMLObjectElement::canLazyAttach): Refuse lazy attach, since
        plugins and frames do important work at rederer creation time.
        * html/HTMLOptGroupElement.cpp:
        (WebCore::HTMLOptGroupElement::insertBefore): Pass along extra param.
        (WebCore::HTMLOptGroupElement::replaceChild): ditto
        (WebCore::HTMLOptGroupElement::appendChild): ditto
        * html/HTMLOptGroupElement.h:
        * html/HTMLSelectElement.cpp:
        (WebCore::HTMLSelectElement::insertBefore): Pass along extra param.
        (WebCore::HTMLSelectElement::replaceChild): ditto
        (WebCore::HTMLSelectElement::appendChild): ditto
        * html/HTMLSelectElement.h:
        * svg/SVGLocatable.cpp:
        (WebCore::SVGLocatable::getBBox): Add missing updateLayout call.
        * svg/SVGTextContentElement.cpp:
        (WebCore::SVGTextContentElement::getNumberOfChars): ditto
        (WebCore::SVGTextContentElement::getComputedTextLength): ditto
        (WebCore::SVGTextContentElement::getSubStringLength): ditto
        (WebCore::SVGTextContentElement::getStartPositionOfChar): ditto
        (WebCore::SVGTextContentElement::getEndPositionOfChar): ditto
        (WebCore::SVGTextContentElement::getExtentOfChar): ditto
        (WebCore::SVGTextContentElement::getRotationOfChar): ditto
        (WebCore::SVGTextContentElement::getCharNumAtPosition): ditto

LayoutTests:

2008-05-29  Maciej Stachowiak  <mjs@apple.com>

        Reviewed by Dave Hyatt.

        - Test cases for this change: "speed up DHTML using lazy style resolution and rendere creation"

        * http/tests/misc/acid3-expected.txt:
        * platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.checksum:
        * platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.png:
        * platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.txt:

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/misc/acid3-expected.txt
LayoutTests/platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.checksum
LayoutTests/platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.png
LayoutTests/platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.txt
WebCore/ChangeLog
WebCore/bindings/js/JSNodeCustom.cpp
WebCore/dom/ContainerNode.cpp
WebCore/dom/ContainerNode.h
WebCore/dom/Element.cpp
WebCore/dom/Node.cpp
WebCore/dom/Node.h
WebCore/dom/Text.cpp
WebCore/html/HTMLEmbedElement.h
WebCore/html/HTMLFrameElementBase.h
WebCore/html/HTMLFrameSetElement.cpp
WebCore/html/HTMLObjectElement.h
WebCore/html/HTMLOptGroupElement.cpp
WebCore/html/HTMLOptGroupElement.h
WebCore/html/HTMLSelectElement.cpp
WebCore/html/HTMLSelectElement.h
WebCore/svg/SVGLocatable.cpp
WebCore/svg/SVGTextContentElement.cpp

index c30722d..89c4985 100644 (file)
@@ -1,3 +1,14 @@
+2008-05-29  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - Test cases for this change: "speed up DHTML using lazy style resolution and rendere creation"
+
+        * http/tests/misc/acid3-expected.txt:
+        * platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.checksum:
+        * platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.png:
+        * platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.txt:
+
 2008-05-28  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Anders.
index 434fa9c..c14771a 100644 (file)
@@ -6,7 +6,6 @@ layer at (20,20) size 644x457
       RenderBlock {H1} at (41,41) size 562x120
         RenderText {#text} at (0,4) size 273x112
           text run at (0,4) width 273: "Acid3"
-      RenderBlock (anonymous) at (41,121) size 562x0
       RenderBlock {DIV} at (41,121) size 562x312
         RenderBlock {P} at (7,80) size 54x42 [bgcolor=#FF0000] [border: (1px solid #000000)]
         RenderBlock {P} at (70,64) size 64x50 [bgcolor=#FFA500] [border: (1px solid #000000)]
index e803cc8..9635269 100644 (file)
Binary files a/LayoutTests/platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.png and b/LayoutTests/platform/mac/fast/dynamic/insert-before-table-part-in-continuation-expected.png differ
index df83be5..37caa6a 100644 (file)
@@ -1,8 +1,8 @@
-layer at (0,0) size 785x742
+layer at (0,0) size 785x678
   RenderView at (0,0) size 785x600
-layer at (0,0) size 785x742
-  RenderBlock {HTML} at (0,0) size 785x742
-    RenderBody {BODY} at (8,8) size 769x726
+layer at (0,0) size 785x678
+  RenderBlock {HTML} at (0,0) size 785x678
+    RenderBody {BODY} at (8,8) size 769x662
       RenderBlock {P} at (0,0) size 769x18
         RenderText {#text} at (0,0) size 53x18
           text run at (0,0) width 53: "Test for "
@@ -23,17 +23,16 @@ layer at (0,0) size 785x742
           text run at (0,54) width 122: "parent was a block."
       RenderBlock {DIV} at (0,122) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
-          RenderInline {SPAN} at (0,0) size 41x18
+          RenderInline {SPAN} at (0,0) size 128x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
+            RenderText {#text} at (41,0) size 87x18
+              text run at (41,0) width 87: "goes here and"
         RenderBlock (anonymous) at (0,18) size 769x18
-          RenderTable at (0,0) size 190x18
-            RenderTableSection (anonymous) at (0,0) size 190x18
-              RenderTableRow (anonymous) at (0,0) size 190x18
-                RenderTableCell (anonymous) at (0,0) size 87x18 [r=0 c=0 rs=1 cs=1]
-                  RenderText {#text} at (0,0) size 87x18
-                    text run at (0,0) width 87: "goes here and"
-                RenderTableCell {DIV} at (87,0) size 103x18 [r=0 c=1 rs=1 cs=1]
+          RenderTable at (0,0) size 103x18
+            RenderTableSection (anonymous) at (0,0) size 103x18
+              RenderTableRow (anonymous) at (0,0) size 103x18
+                RenderTableCell {DIV} at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
         RenderBlock (anonymous) at (0,36) size 769x0
@@ -73,13 +72,12 @@ layer at (0,0) size 785x742
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
+            RenderInline {SPAN} at (0,0) size 0x18
         RenderBlock (anonymous) at (0,18) size 769x18
-          RenderTable at (0,0) size 104x18
-            RenderTableSection (anonymous) at (0,0) size 104x18
-              RenderTableRow (anonymous) at (0,0) size 104x18
-                RenderTableCell (anonymous) at (0,0) size 1x0 [r=0 c=0 rs=1 cs=1]
-                  RenderInline {SPAN} at (0,0) size 0x0
-                RenderTableCell {DIV} at (1,0) size 103x18 [r=0 c=1 rs=1 cs=1]
+          RenderTable at (0,0) size 103x18
+            RenderTableSection (anonymous) at (0,0) size 103x18
+              RenderTableRow (anonymous) at (0,0) size 103x18
+                RenderTableCell {DIV} at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
         RenderBlock (anonymous) at (0,36) size 769x0
@@ -90,35 +88,32 @@ layer at (0,0) size 785x742
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
         RenderBlock (anonymous) at (0,18) size 769x18
-          RenderTable at (0,0) size 104x18
-            RenderTableSection (anonymous) at (0,0) size 104x18
-              RenderTableRow (anonymous) at (0,0) size 104x18
-                RenderTableCell (anonymous) at (0,14) size 1x0 [r=0 c=0 rs=1 cs=1]
-                  RenderBlock {DIV} at (0,0) size 1x0
-                RenderTableCell {DIV} at (1,0) size 103x18 [r=0 c=1 rs=1 cs=1]
+          RenderTable at (0,0) size 103x18
+            RenderTableSection (anonymous) at (0,0) size 103x18
+              RenderTableRow (anonymous) at (0,0) size 103x18
+                RenderTableCell {DIV} at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
+          RenderBlock {DIV} at (0,18) size 769x0
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,302) size 769x54
+      RenderBlock {DIV} at (0,302) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
-          RenderInline {SPAN} at (0,0) size 41x18
+          RenderInline {SPAN} at (0,0) size 128x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
-        RenderBlock (anonymous) at (0,18) size 769x36
-          RenderTable at (0,0) size 103x36
-            RenderTableSection (anonymous) at (0,0) size 103x36
-              RenderTableRow (anonymous) at (0,0) size 103x18
+            RenderText {#text} at (41,0) size 87x18
+              text run at (41,0) width 87: "goes here and"
+        RenderBlock (anonymous) at (0,18) size 769x18
+          RenderTable at (0,0) size 103x18
+            RenderTableSection (anonymous) at (0,0) size 103x18
+              RenderTableRow {DIV} at (0,0) size 103x18
                 RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
-                  RenderText {#text} at (0,0) size 87x18
-                    text run at (0,0) width 87: "goes here and"
-              RenderTableRow {DIV} at (0,18) size 103x18
-                RenderTableCell (anonymous) at (0,18) size 103x18 [r=1 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
-        RenderBlock (anonymous) at (0,54) size 769x0
+        RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,356) size 769x36
+      RenderBlock {DIV} at (0,338) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
@@ -134,7 +129,7 @@ layer at (0,0) size 785x742
                     text run at (0,0) width 103: "...continues here"
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,392) size 769x36
+      RenderBlock {DIV} at (0,374) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
@@ -149,24 +144,22 @@ layer at (0,0) size 785x742
                     text run at (0,0) width 103: "...continues here"
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,428) size 769x50
+      RenderBlock {DIV} at (0,410) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
-        RenderBlock (anonymous) at (0,18) size 769x32
-          RenderTable at (0,0) size 103x32
-            RenderTableSection (anonymous) at (0,0) size 103x32
-              RenderTableRow (anonymous) at (0,0) size 103x14
-                RenderTableCell (anonymous) at (0,0) size 103x0 [r=0 c=0 rs=1 cs=1]
-                  RenderInline {SPAN} at (0,0) size 0x0
-              RenderTableRow {DIV} at (0,14) size 103x18
-                RenderTableCell (anonymous) at (0,14) size 103x18 [r=1 c=0 rs=1 cs=1]
+            RenderInline {SPAN} at (0,0) size 0x18
+        RenderBlock (anonymous) at (0,18) size 769x18
+          RenderTable at (0,0) size 103x18
+            RenderTableSection (anonymous) at (0,0) size 103x18
+              RenderTableRow {DIV} at (0,0) size 103x18
+                RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
-        RenderBlock (anonymous) at (0,50) size 769x0
+        RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,478) size 769x36
+      RenderBlock {DIV} at (0,446) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
@@ -174,35 +167,30 @@ layer at (0,0) size 785x742
         RenderBlock (anonymous) at (0,18) size 769x18
           RenderTable at (0,0) size 103x18
             RenderTableSection (anonymous) at (0,0) size 103x18
-              RenderTableRow (anonymous) at (0,0) size 103x0
-                RenderTableCell (anonymous) at (0,0) size 103x0 [r=0 c=0 rs=1 cs=1]
-                  RenderBlock {DIV} at (0,0) size 103x0
               RenderTableRow {DIV} at (0,0) size 103x18
-                RenderTableCell (anonymous) at (0,0) size 103x18 [r=1 c=0 rs=1 cs=1]
+                RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
+          RenderBlock {DIV} at (0,18) size 769x0
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,514) size 769x54
+      RenderBlock {DIV} at (0,482) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
-          RenderInline {SPAN} at (0,0) size 41x18
+          RenderInline {SPAN} at (0,0) size 128x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
-        RenderBlock (anonymous) at (0,18) size 769x36
-          RenderTable at (0,0) size 103x36
-            RenderTableSection (anonymous) at (0,0) size 103x18
-              RenderTableRow (anonymous) at (0,0) size 103x18
-                RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
-                  RenderText {#text} at (0,0) size 87x18
-                    text run at (0,0) width 87: "goes here and"
-            RenderTableSection {DIV} at (0,18) size 103x18
+            RenderText {#text} at (41,0) size 87x18
+              text run at (41,0) width 87: "goes here and"
+        RenderBlock (anonymous) at (0,18) size 769x18
+          RenderTable at (0,0) size 103x18
+            RenderTableSection {DIV} at (0,0) size 103x18
               RenderTableRow (anonymous) at (0,0) size 103x18
                 RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
-        RenderBlock (anonymous) at (0,54) size 769x0
+        RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,568) size 769x36
+      RenderBlock {DIV} at (0,518) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
@@ -219,7 +207,7 @@ layer at (0,0) size 785x742
                     text run at (0,0) width 103: "...continues here"
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,604) size 769x36
+      RenderBlock {DIV} at (0,554) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
@@ -235,39 +223,33 @@ layer at (0,0) size 785x742
                     text run at (0,0) width 103: "...continues here"
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,640) size 769x50
+      RenderBlock {DIV} at (0,590) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
-        RenderBlock (anonymous) at (0,18) size 769x32
-          RenderTable at (0,0) size 103x32
-            RenderTableSection (anonymous) at (0,0) size 103x14
-              RenderTableRow (anonymous) at (0,0) size 103x14
-                RenderTableCell (anonymous) at (0,0) size 103x0 [r=0 c=0 rs=1 cs=1]
-                  RenderInline {SPAN} at (0,0) size 0x0
-            RenderTableSection {DIV} at (0,14) size 103x18
+            RenderInline {SPAN} at (0,0) size 0x18
+        RenderBlock (anonymous) at (0,18) size 769x18
+          RenderTable at (0,0) size 103x18
+            RenderTableSection {DIV} at (0,0) size 103x18
               RenderTableRow (anonymous) at (0,0) size 103x18
                 RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
-        RenderBlock (anonymous) at (0,50) size 769x0
+        RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
-      RenderBlock {DIV} at (0,690) size 769x36
+      RenderBlock {DIV} at (0,626) size 769x36
         RenderBlock (anonymous) at (0,0) size 769x18
           RenderInline {SPAN} at (0,0) size 41x18
             RenderText {#text} at (0,0) size 41x18
               text run at (0,0) width 41: "Text..."
         RenderBlock (anonymous) at (0,18) size 769x18
           RenderTable at (0,0) size 103x18
-            RenderTableSection (anonymous) at (0,0) size 103x0
-              RenderTableRow (anonymous) at (0,0) size 103x0
-                RenderTableCell (anonymous) at (0,0) size 103x0 [r=0 c=0 rs=1 cs=1]
-                  RenderBlock {DIV} at (0,0) size 103x0
             RenderTableSection {DIV} at (0,0) size 103x18
               RenderTableRow (anonymous) at (0,0) size 103x18
                 RenderTableCell (anonymous) at (0,0) size 103x18 [r=0 c=0 rs=1 cs=1]
                   RenderText {#text} at (0,0) size 103x18
                     text run at (0,0) width 103: "...continues here"
+          RenderBlock {DIV} at (0,18) size 769x0
         RenderBlock (anonymous) at (0,36) size 769x0
           RenderInline {SPAN} at (0,0) size 0x0
index 3874b99..81356a0 100644 (file)
@@ -1,3 +1,84 @@
+2008-05-29  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - speed up DHTML using lazy style resolution and rendere creation
+
+        This change introduces the concept of "lazy attach" - when a node
+        is lazy attached, then instead of resolving style and creating a
+        renderer right away, we just mark it as needing a style recalc.
+        
+        The patch makes use of this mechanism when inserting nodes directly
+        using DOM APIs from script. For now this is only done for the
+        JavaScript language binding but could also be done for other
+        bindings in the future.
+        
+        Lazy attach helps some common DHTML patterns - when a node is
+        added to the DOM, and then subsequently changed in a
+        style-affecting way, this causes an extra style recalc. This is a
+        fairly common pattern so it is better to be lazy.
+        
+        * bindings/js/JSNodeCustom.cpp:
+        (WebCore::JSNode::insertBefore): Request lazy attach.
+        (WebCore::JSNode::replaceChild): ditto
+        (WebCore::JSNode::appendChild): ditto
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::insertBefore): Support lazy attach.
+        (WebCore::ContainerNode::replaceChild): ditto
+        (WebCore::ContainerNode::appendChild): ditto
+        (WebCore::ContainerNode::detach): Clear "changed child" bit if still set.
+        * dom/ContainerNode.h:
+        * dom/Element.cpp:
+        (WebCore::Element::recalcStyle): Adjusted to properly reattach a
+        lazy-attached node.
+        * dom/Node.cpp:
+        (WebCore::Node::insertBefore): Extra parameter for lazy attach
+        (still doesn't do anything).
+        (WebCore::Node::replaceChild): ditto
+        (WebCore::Node::appendChild): ditto
+        (WebCore::Node::setChanged): Unrelated but obvious optimization -
+        stop marking ancestor as having a changed child once we already reach
+        an ancestor so marked.
+        (WebCore::outermostLazyAttachedAncestor): Helper function for lazyAttach.
+        (WebCore::Node::lazyAttach): Implement lazy attach.
+        (WebCore::Node::canLazyAttach): Virtual method - true for most nodes.
+        * dom/Node.h:
+        * dom/Text.cpp:
+        (WebCore::Text::recalcStyle): Properly handle the case of a reattached node.
+        * html/HTMLEmbedElement.h:
+        (WebCore::HTMLEmbedElement::canLazyAttach): Refuse lazy attach, since
+        plugins and frames do important work at rederer creation time.
+        * html/HTMLFrameElementBase.h:
+        (WebCore::HTMLFrameElementBase::canLazyAttach): Refuse lazy attach, since
+        plugins and frames do important work at rederer creation time.
+        * html/HTMLFrameSetElement.cpp:
+        (WebCore::HTMLFrameSetElement::recalcStyle): Change order so that
+        reattach works properly.
+        * html/HTMLObjectElement.h:
+        (WebCore::HTMLObjectElement::canLazyAttach): Refuse lazy attach, since
+        plugins and frames do important work at rederer creation time.
+        * html/HTMLOptGroupElement.cpp:
+        (WebCore::HTMLOptGroupElement::insertBefore): Pass along extra param.
+        (WebCore::HTMLOptGroupElement::replaceChild): ditto
+        (WebCore::HTMLOptGroupElement::appendChild): ditto
+        * html/HTMLOptGroupElement.h:
+        * html/HTMLSelectElement.cpp:
+        (WebCore::HTMLSelectElement::insertBefore): Pass along extra param.
+        (WebCore::HTMLSelectElement::replaceChild): ditto
+        (WebCore::HTMLSelectElement::appendChild): ditto
+        * html/HTMLSelectElement.h:
+        * svg/SVGLocatable.cpp:
+        (WebCore::SVGLocatable::getBBox): Add missing updateLayout call.
+        * svg/SVGTextContentElement.cpp:
+        (WebCore::SVGTextContentElement::getNumberOfChars): ditto
+        (WebCore::SVGTextContentElement::getComputedTextLength): ditto
+        (WebCore::SVGTextContentElement::getSubStringLength): ditto
+        (WebCore::SVGTextContentElement::getStartPositionOfChar): ditto
+        (WebCore::SVGTextContentElement::getEndPositionOfChar): ditto
+        (WebCore::SVGTextContentElement::getExtentOfChar): ditto
+        (WebCore::SVGTextContentElement::getRotationOfChar): ditto
+        (WebCore::SVGTextContentElement::getCharNumAtPosition): ditto
+
 2008-05-28  Ada Chan  <adachan@apple.com>
 
         <rdar://problem/5957036> REGRESSION (r31960): 20-30% slowdown in i-Bench JavaScript test on XP Home
index c558145..4db46d7 100644 (file)
@@ -69,7 +69,7 @@ typedef int ExpectionCode;
 JSValue* JSNode::insertBefore(ExecState* exec, const List& args)
 {
     ExceptionCode ec = 0;
-    bool ok = impl()->insertBefore(toNode(args[0]), toNode(args[1]), ec);
+    bool ok = impl()->insertBefore(toNode(args[0]), toNode(args[1]), ec, true);
     setDOMException(exec, ec);
     if (ok)
         return args[0];
@@ -79,7 +79,7 @@ JSValue* JSNode::insertBefore(ExecState* exec, const List& args)
 JSValue* JSNode::replaceChild(ExecState* exec, const List& args)
 {
     ExceptionCode ec = 0;
-    bool ok = impl()->replaceChild(toNode(args[0]), toNode(args[1]), ec);
+    bool ok = impl()->replaceChild(toNode(args[0]), toNode(args[1]), ec, true);
     setDOMException(exec, ec);
     if (ok)
         return args[1];
@@ -99,7 +99,7 @@ JSValue* JSNode::removeChild(ExecState* exec, const List& args)
 JSValue* JSNode::appendChild(ExecState* exec, const List& args)
 {
     ExceptionCode ec = 0;
-    bool ok = impl()->appendChild(toNode(args[0]), ec);
+    bool ok = impl()->appendChild(toNode(args[0]), ec, true);
     setDOMException(exec, ec);
     if (ok)
         return args[0];
index 7082fe6..2942acf 100644 (file)
@@ -128,7 +128,7 @@ Node* ContainerNode::virtualLastChild() const
     return m_lastChild;
 }
 
-bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec)
+bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
     // Check that this node is not "floating".
     // If it is, it can be deleted as a side effect of sending mutation events.
@@ -138,7 +138,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
 
     // insertBefore(node, 0) is equivalent to appendChild(node)
     if (!refChild)
-        return appendChild(newChild, ec);
+        return appendChild(newChild, ec, shouldLazyAttach);
 
     // Make sure adding the new child is OK.
     checkAddChild(newChild.get(), ec);
@@ -217,8 +217,12 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
         dispatchChildInsertionEvents(child.get(), ec);
                 
         // Add child to the rendering tree.
-        if (attached() && !child->attached() && child->parent() == this)
-            child->attach();
+        if (attached() && !child->attached() && child->parent() == this) {
+            if (shouldLazyAttach)
+                child->lazyAttach();
+            else
+                child->attach();
+        }
 
         child = nextChild.release();
     }
@@ -230,7 +234,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
     return true;
 }
 
-bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec)
+bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
     // Check that this node is not "floating".
     // If it is, it can be deleted as a side effect of sending mutation events.
@@ -327,8 +331,12 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
         dispatchChildInsertionEvents(child.get(), ec);
                 
         // Add child to the rendering tree
-        if (attached() && !child->attached() && child->parent() == this)
-            child->attach();
+        if (attached() && !child->attached() && child->parent() == this) {
+            if (shouldLazyAttach)
+                child->lazyAttach();
+            else
+                child->attach();
+        }
 
         prev = child;
         child = nextChild.release();
@@ -502,7 +510,7 @@ bool ContainerNode::removeChildren()
     return true;
 }
 
-bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
+bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
     // Check that this node is not "floating".
     // If it is, it can be deleted as a side effect of sending mutation events.
@@ -562,8 +570,12 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
         dispatchChildInsertionEvents(child.get(), ec);
 
         // Add child to the rendering tree
-        if (attached() && !child->attached() && child->parent() == this)
-            child->attach();
+        if (attached() && !child->attached() && child->parent() == this) {
+            if (shouldLazyAttach)
+                child->lazyAttach();
+            else
+                child->attach();
+        }
         
         child = nextChild.release();
     }
@@ -655,6 +667,7 @@ void ContainerNode::detach()
 {
     for (Node* child = m_firstChild; child; child = child->nextSibling())
         child->detach();
+    setHasChangedChild(false);
     EventTargetNode::detach();
 }
 
index 28563f2..70429fa 100644 (file)
@@ -38,10 +38,10 @@ public:
     Node* firstChild() const { return m_firstChild; }
     Node* lastChild() const { return m_lastChild; }
 
-    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&);
-    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&);
+    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&, bool shouldLazyAttach = false);
+    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&, bool shouldLazyAttach = false);
     virtual bool removeChild(Node* child, ExceptionCode&);
-    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&);
+    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false);
 
     virtual ContainerNode* addChild(PassRefPtr<Node>);
     bool hasChildNodes() const { return m_firstChild; }
index a32794b..525202d 100644 (file)
@@ -757,7 +757,7 @@ void Element::recalcStyle(StyleChange change)
     if (hasParentStyle && (change >= Inherit || changed())) {
         RenderStyle *newStyle = document()->styleSelector()->styleForElement(this);
         StyleChange ch = diff(currentStyle, newStyle);
-        if (ch == Detach) {
+        if (ch == Detach || !currentStyle) {
             if (attached())
                 detach();
             // ### Suboptimal. Style gets calculated again.
index cd91ec4..ab7c5b4 100644 (file)
@@ -244,13 +244,13 @@ Node* Node::firstDescendant() const
     return n;
 }
 
-bool Node::insertBefore(PassRefPtr<Node>, Node*, ExceptionCode& ec)
+bool Node::insertBefore(PassRefPtr<Node>, Node*, ExceptionCode& ec, bool)
 {
     ec = HIERARCHY_REQUEST_ERR;
     return false;
 }
 
-bool Node::replaceChild(PassRefPtr<Node>, Node*, ExceptionCode& ec)
+bool Node::replaceChild(PassRefPtr<Node>, Node*, ExceptionCode& ec, bool)
 {
     ec = HIERARCHY_REQUEST_ERR;
     return false;
@@ -262,7 +262,7 @@ bool Node::removeChild(Node*, ExceptionCode& ec)
     return false;
 }
 
-bool Node::appendChild(PassRefPtr<Node>, ExceptionCode& ec)
+bool Node::appendChild(PassRefPtr<Node>, ExceptionCode& ec, bool)
 {
     ec = HIERARCHY_REQUEST_ERR;
     return false;
@@ -383,12 +383,52 @@ void Node::setChanged(StyleChangeType changeType)
         m_styleChange = changeType;
 
     if (m_styleChange != NoStyleChange) {
-        for (Node* p = parentNode(); p; p = p->parentNode())
+        for (Node* p = parentNode(); p && !p->hasChangedChild(); p = p->parentNode())
             p->setHasChangedChild(true);
         document()->setDocumentChanged(true);
     }
 }
 
+static Node* outermostLazyAttachedAncestor(Node* start)
+{
+    Node* p = start;
+    for (Node* next = p->parentNode(); !next->renderer(); p = next, next = next->parentNode()) {}
+    return p;
+}
+
+void Node::lazyAttach()
+{
+    bool mustDoFullAttach = false;
+
+    for (Node* n = this; n; n = n->traverseNextNode(this)) {
+        if (!n->canLazyAttach()) {
+            mustDoFullAttach = true;
+            break;
+        }
+
+        if (n->firstChild())
+            n->setHasChangedChild(true);
+        n->m_styleChange = FullStyleChange;
+        n->m_attached = true;
+    }
+
+    if (mustDoFullAttach) {
+        Node* lazyAttachedAncestor = outermostLazyAttachedAncestor(this);
+        if (lazyAttachedAncestor->attached())
+            lazyAttachedAncestor->detach();
+        lazyAttachedAncestor->attach();
+    } else {
+        for (Node* p = parentNode(); p && !p->hasChangedChild(); p = p->parentNode())
+            p->setHasChangedChild(true);
+        document()->setDocumentChanged(true);
+    }
+}
+
+bool Node::canLazyAttach()
+{
+    return shadowAncestorNode() == this;
+}
+
 bool Node::isFocusable() const
 {
     return m_tabIndexSetExplicitly;
index cd1792e..2494b45 100644 (file)
@@ -114,10 +114,10 @@ public:
     // These should all actually return a node, but this is only important for language bindings,
     // which will already know and hold a ref on the right node to return. Returning bool allows
     // these methods to be more efficient since they don't need to return a ref
-    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&);
-    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&);
+    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&, bool shouldLazyAttach = false);
+    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&, bool shouldLazyAttach = false);
     virtual bool removeChild(Node* child, ExceptionCode&);
-    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&);
+    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false);
 
     virtual void remove(ExceptionCode&);
     bool hasChildNodes() const { return firstChild(); }
@@ -248,6 +248,9 @@ public:
     void setInActiveChain(bool b = true) { m_inActiveChain = b; }
     void setChanged(StyleChangeType changeType = FullStyleChange);
 
+    void lazyAttach();
+    virtual bool canLazyAttach();
+
     virtual void setFocus(bool b = true) { m_focused = b; }
     virtual void setActive(bool b = true, bool pause=false) { m_active = b; }
     virtual void setHovered(bool b = true) { m_hovered = b; }
index 61f90c3..723997e 100644 (file)
@@ -248,8 +248,16 @@ void Text::recalcStyle(StyleChange change)
         if (renderer())
             renderer()->setStyle(parentNode()->renderer()->style());
     }
-    if (changed() && renderer() && renderer()->isText())
-        static_cast<RenderText*>(renderer())->setText(m_data);
+    if (changed()) {
+        if (renderer()) {
+            if (renderer()->isText())
+                static_cast<RenderText*>(renderer())->setText(m_data);
+        } else {
+            if (attached())
+                detach();
+            attach();
+        }
+    }
     setChanged(NoStyleChange);
 }
 
index c852bd5..fb4bc4d 100644 (file)
@@ -47,6 +47,7 @@ public:
     virtual void parseMappedAttribute(MappedAttribute*);
 
     virtual void attach();
+    virtual bool canLazyAttach() { return false; }
     virtual void detach();
     virtual bool rendererIsNeeded(RenderStyle*);
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
index 62b7bd8..4a24451 100644 (file)
@@ -37,6 +37,7 @@ public:
     virtual void removedFromDocument();
 
     virtual void attach();
+    virtual bool canLazyAttach() { return false; }
 
     KURL location() const;
     void setLocation(const String&);
index 1bd15a9..71a8e82 100644 (file)
@@ -187,11 +187,11 @@ void HTMLFrameSetElement::defaultEventHandler(Event* evt)
 
 void HTMLFrameSetElement::recalcStyle(StyleChange ch)
 {
+    HTMLElement::recalcStyle(ch);
     if (changed() && renderer()) {
         renderer()->setNeedsLayout(true);
         setChanged(NoStyleChange);
     }
-    HTMLElement::recalcStyle(ch);
 }
 
 String HTMLFrameSetElement::cols() const
index 295f6e2..f50c038 100644 (file)
@@ -41,6 +41,7 @@ public:
     virtual void parseMappedAttribute(MappedAttribute*);
 
     virtual void attach();
+    virtual bool canLazyAttach() { return false; }
     virtual bool rendererIsNeeded(RenderStyle*);
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
     virtual void finishParsingChildren();
index 7132ae0..afa230c 100644 (file)
@@ -52,17 +52,17 @@ const AtomicString& HTMLOptGroupElement::type() const
     return optgroup;
 }
 
-bool HTMLOptGroupElement::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec)
+bool HTMLOptGroupElement::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
-    bool result = HTMLGenericFormElement::insertBefore(newChild, refChild, ec);
+    bool result = HTMLGenericFormElement::insertBefore(newChild, refChild, ec, shouldLazyAttach);
     if (result)
         recalcSelectOptions();
     return result;
 }
 
-bool HTMLOptGroupElement::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec)
+bool HTMLOptGroupElement::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
-    bool result = HTMLGenericFormElement::replaceChild(newChild, oldChild, ec);
+    bool result = HTMLGenericFormElement::replaceChild(newChild, oldChild, ec, shouldLazyAttach);
     if (result)
         recalcSelectOptions();
     return result;
@@ -76,9 +76,9 @@ bool HTMLOptGroupElement::removeChild(Node* oldChild, ExceptionCode& ec)
     return result;
 }
 
-bool HTMLOptGroupElement::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
+bool HTMLOptGroupElement::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
-    bool result = HTMLGenericFormElement::appendChild(newChild, ec);
+    bool result = HTMLGenericFormElement::appendChild(newChild, ec, shouldLazyAttach);
     if (result)
         recalcSelectOptions();
     return result;
index c635a32..f7124ea 100644 (file)
@@ -44,10 +44,10 @@ public:
     virtual RenderStyle* renderStyle() const { return m_style; }
     virtual void setRenderStyle(RenderStyle*);
 
-    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&);
-    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&);
+    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&, bool shouldLazyAttach = false);
+    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&, bool shouldLazyAttach = false);
     virtual bool removeChild(Node* child, ExceptionCode&);
-    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&);
+    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false);
     virtual bool removeChildren();
     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
 
index 6a7cebc..3f7799b 100644 (file)
@@ -302,17 +302,17 @@ void HTMLSelectElement::restoreState(const String& state)
     setChanged();
 }
 
-bool HTMLSelectElement::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec)
+bool HTMLSelectElement::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
-    bool result = HTMLFormControlElementWithState::insertBefore(newChild, refChild, ec);
+    bool result = HTMLFormControlElementWithState::insertBefore(newChild, refChild, ec, shouldLazyAttach);
     if (result)
         setRecalcListItems();
     return result;
 }
 
-bool HTMLSelectElement::replaceChild(PassRefPtr<Node> newChild, Node *oldChild, ExceptionCode& ec)
+bool HTMLSelectElement::replaceChild(PassRefPtr<Node> newChild, Node *oldChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
-    bool result = HTMLFormControlElementWithState::replaceChild(newChild, oldChild, ec);
+    bool result = HTMLFormControlElementWithState::replaceChild(newChild, oldChild, ec, shouldLazyAttach);
     if (result)
         setRecalcListItems();
     return result;
@@ -326,9 +326,9 @@ bool HTMLSelectElement::removeChild(Node* oldChild, ExceptionCode& ec)
     return result;
 }
 
-bool HTMLSelectElement::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
+bool HTMLSelectElement::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bool shouldLazyAttach)
 {
-    bool result = HTMLFormControlElementWithState::appendChild(newChild, ec);
+    bool result = HTMLFormControlElementWithState::appendChild(newChild, ec, shouldLazyAttach);
     if (result)
         setRecalcListItems();
     return result;
index 3117e0f..af142e4 100644 (file)
@@ -82,10 +82,10 @@ public:
     virtual bool saveState(String& value) const;
     virtual void restoreState(const String&);
 
-    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&);
-    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&);
+    virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&, bool shouldLazyAttach = false);
+    virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&, bool shouldLazyAttach = false);
     virtual bool removeChild(Node* child, ExceptionCode&);
-    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&);
+    virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false);
     virtual bool removeChildren();
     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
 
index 91564a5..65192fa 100644 (file)
@@ -87,10 +87,11 @@ FloatRect SVGLocatable::getBBox(const SVGStyledElement* e)
 {
     FloatRect bboxRect;
 
+    e->document()->updateLayoutIgnorePendingStylesheets();
+
     if (e && e->renderer()) {
         // Need this to make sure we have render object dimensions.
         // See bug 11686.
-        e->document()->updateLayoutIgnorePendingStylesheets();
         bboxRect = e->renderer()->relativeBBox(false);
     }
 
index 2ebf4b9..3eddb2d 100644 (file)
@@ -369,16 +369,22 @@ static inline SVGInlineTextBoxQueryWalker executeTextQuery(const SVGTextContentE
 
 long SVGTextContentElement::getNumberOfChars() const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     return executeTextQuery(this, SVGInlineTextBoxQueryWalker::NumberOfCharacters).longResult();
 }
 
 float SVGTextContentElement::getComputedTextLength() const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     return executeTextQuery(this, SVGInlineTextBoxQueryWalker::TextLength).floatResult();
 }
 
 float SVGTextContentElement::getSubStringLength(long charnum, long nchars, ExceptionCode& ec) const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     // Differences to SVG 1.1 spec, as the spec is clearly wrong. TODO: Raise SVG WG issue!
     // #1: We accept a 'long nchars' parameter instead of 'unsigned long nchars' to be able
     //     to catch cases where someone called us with a negative 'nchars' value - in those
@@ -401,6 +407,8 @@ float SVGTextContentElement::getSubStringLength(long charnum, long nchars, Excep
 
 FloatPoint SVGTextContentElement::getStartPositionOfChar(long charnum, ExceptionCode& ec) const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     if (charnum < 0 || charnum > getNumberOfChars()) {
         ec = INDEX_SIZE_ERR;
         return FloatPoint();
@@ -411,6 +419,8 @@ FloatPoint SVGTextContentElement::getStartPositionOfChar(long charnum, Exception
 
 FloatPoint SVGTextContentElement::getEndPositionOfChar(long charnum, ExceptionCode& ec) const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     if (charnum < 0 || charnum > getNumberOfChars()) {
         ec = INDEX_SIZE_ERR;
         return FloatPoint();
@@ -421,6 +431,8 @@ FloatPoint SVGTextContentElement::getEndPositionOfChar(long charnum, ExceptionCo
 
 FloatRect SVGTextContentElement::getExtentOfChar(long charnum, ExceptionCode& ec) const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     if (charnum < 0 || charnum > getNumberOfChars()) {
         ec = INDEX_SIZE_ERR;
         return FloatRect();
@@ -431,6 +443,8 @@ FloatRect SVGTextContentElement::getExtentOfChar(long charnum, ExceptionCode& ec
 
 float SVGTextContentElement::getRotationOfChar(long charnum, ExceptionCode& ec) const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     if (charnum < 0 || charnum > getNumberOfChars()) {
         ec = INDEX_SIZE_ERR;
         return 0.0f;
@@ -441,6 +455,8 @@ float SVGTextContentElement::getRotationOfChar(long charnum, ExceptionCode& ec)
 
 long SVGTextContentElement::getCharNumAtPosition(const FloatPoint& point) const
 {
+    document()->updateLayoutIgnorePendingStylesheets();
+
     return executeTextQuery(this, SVGInlineTextBoxQueryWalker::CharacterNumberAtPosition, 0.0f, 0.0f, point).longResult();
 }