LayoutTests/imported/w3c:
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Sep 2019 14:31:37 +0000 (14:31 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Sep 2019 14:31:37 +0000 (14:31 +0000)
    Eliminate separate simple line layout path from TextIterator
    https://bugs.webkit.org/show_bug.cgi?id=201760

    Reviewed by Zalan Bujtas.

    * web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015-expected.txt:
    * web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016-expected.txt:
    * web-platform-tests/innerText/getter-expected.txt:

    Two '\t' subtests flip to FAIL because this was only supported on TextIterator simple line layout path.
    This can now be fixed correctly for both paths.

Source/WebCore:
Eliminate separate simple line layout path from TextIterator
https://bugs.webkit.org/show_bug.cgi?id=201760

Reviewed by Zalan Bujtas.

Use the new line layout iterator to implement linebox traversal in TextIterator.

* WebCore.xcodeproj/project.pbxproj:
* editing/TextIterator.cpp:
(WebCore::TextIterator::advance):
(WebCore::TextIterator::handleTextNode):
(WebCore::TextIterator::handleTextBox):

InlineTextBox* -> LineLayoutInterface::TextBoxIterator
Delete the seperate simple line layout path.

(WebCore::TextIterator::handleTextNodeFirstLetter):
(WebCore::TextIterator::emitCharacter):
(WebCore::TextIterator::emitText):
* editing/TextIterator.h:
* rendering/RenderTreeAsText.cpp:
(WebCore::RenderTreeAsText::writeRenderObject):
(WebCore::write):
* rendering/SimpleLineLayoutResolver.cpp:
(WebCore::SimpleLineLayout::RunResolver::Iterator::Iterator):
(WebCore::SimpleLineLayout::RunResolver::Iterator::advanceLines):
* rendering/SimpleLineLayoutResolver.h:
(WebCore::SimpleLineLayout::RunResolver::Iterator::resolver const):
(WebCore::SimpleLineLayout::RunResolver::Iterator::inQuirksMode const):
(WebCore::SimpleLineLayout::RunResolver::Iterator::operator== const):
(WebCore::SimpleLineLayout::RunResolver::Iterator::simpleRun const):

Make RunResolver::Iterator copyable (so TextBoxIterator becomes copyable too).

* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::findNextTextFragment):
* rendering/line/LineLayoutInterfaceTextBoxes.cpp:
(WebCore::LineLayoutInterface::TextBox::rect const):
(WebCore::LineLayoutInterface::TextBox::logicalRect const):
(WebCore::LineLayoutInterface::TextBox::hasHyphen const):
(WebCore::LineLayoutInterface::TextBox::isLeftToRightDirection const):
(WebCore::LineLayoutInterface::TextBox::dirOverride const):
(WebCore::LineLayoutInterface::TextBox::text const):
(WebCore::LineLayoutInterface::TextBox::localStartOffset const):
(WebCore::LineLayoutInterface::TextBox::localEndOffset const):
(WebCore::LineLayoutInterface::TextBox::length const):

Add offset and length functions.

(WebCore::LineLayoutInterface::TextBox::iterator const):
(WebCore::LineLayoutInterface::TextBoxIterator::TextBoxIterator):
(WebCore::LineLayoutInterface::TextBoxIterator::traverseNext):
(WebCore::LineLayoutInterface::TextBoxIterator::operator== const):
(WebCore::LineLayoutInterface::TextBoxIterator::atEnd const):
(WebCore::LineLayoutInterface::Provider::firstTextBoxFor):
(WebCore::LineLayoutInterface::Provider::textBoxRangeFor):
(WebCore::LineLayoutInterface::Provider::iteratorForInlineTextBox):

Add Provider class for making iterators. It constructs and keeps SimpleLineLayout::Resolvers alive during traversal as needed.

* rendering/line/LineLayoutInterfaceTextBoxes.h:
(WebCore::LineLayoutInterface::TextBoxIterator::TextBoxIterator):
(WebCore::LineLayoutInterface::TextBoxIterator::operator bool const):
(WebCore::LineLayoutInterface::TextBoxIterator::operator== const):
(WebCore::LineLayoutInterface::TextBoxIterator::operator!= const):
(WebCore::LineLayoutInterface::TextBoxIterator::operator* const):
(WebCore::LineLayoutInterface::TextBoxIterator::operator-> const):

Make TextBoxIterator privately inherit TextBox. This way we don't need to construct temporaries and can easily implement operator->.

(WebCore::LineLayoutInterface::TextBoxRange::TextBoxRange):
(WebCore::LineLayoutInterface::TextBoxRange::begin const):
(WebCore::LineLayoutInterface::TextBoxRange::end const):

Use separate end() type of C++17 ranges.

LayoutTests:
Eliminate separate simple line layout path from TextIterator
https://bugs.webkit.org/show_bug.cgi?id=201760

Reviewed by Zalan Bujtas.

This patch makes simple and complex line layout path results from TextIterator match, causing some whitespace changes.

* animations/lineheight-animation-expected.txt:
* animations/simultaneous-start-transform-expected.txt:
* animations/width-using-ems-expected.txt:
* compositing/shared-backing/overflow-scroll/absolute-in-stacking-relative-in-scroller-expected.txt:
* css3/filters/backdrop/backdrop-filter-does-not-size-properly-absolute-expected.txt:
* fast/events/window-events-bubble-expected.txt:
* fast/events/window-events-bubble2-expected.txt:
* fast/tokenizer/script_extra_close-expected.txt:
* legacy-animation-engine/animations/lineheight-animation-expected.txt:
* legacy-animation-engine/animations/simultaneous-start-transform-expected.txt:
* scrollingcoordinator/scrolling-tree/nested-absolute-in-overflow-expected.txt:

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

31 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/lineheight-animation-expected.txt
LayoutTests/animations/simultaneous-start-transform-expected.txt
LayoutTests/animations/width-using-ems-expected.txt
LayoutTests/compositing/shared-backing/overflow-scroll/absolute-in-stacking-relative-in-scroller-expected.txt
LayoutTests/css3/filters/backdrop/backdrop-filter-does-not-size-properly-absolute-expected.txt
LayoutTests/fast/events/window-events-bubble-expected.txt
LayoutTests/fast/events/window-events-bubble2-expected.txt
LayoutTests/fast/tokenizer/script_extra_close-expected.txt
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015-expected.txt
LayoutTests/imported/w3c/web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016-expected.txt
LayoutTests/imported/w3c/web-platform-tests/html/dom/elements/the-innertext-idl-attribute/getter-expected.txt
LayoutTests/imported/w3c/web-platform-tests/innerText/getter-expected.txt
LayoutTests/legacy-animation-engine/animations/lineheight-animation-expected.txt
LayoutTests/legacy-animation-engine/animations/simultaneous-start-transform-expected.txt
LayoutTests/legacy-animation-engine/animations/width-using-ems-expected.txt
LayoutTests/platform/ios-wk2/compositing/shared-backing/overflow-scroll/absolute-in-stacking-relative-in-scroller-expected.txt
LayoutTests/platform/ios-wk2/scrollingcoordinator/scrolling-tree/nested-absolute-in-overflow-expected.txt
LayoutTests/platform/ios/css3/filters/backdrop/backdrop-filter-does-not-size-properly-absolute-expected.txt
LayoutTests/scrollingcoordinator/scrolling-tree/nested-absolute-in-overflow-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/editing/TextIterator.cpp
Source/WebCore/editing/TextIterator.h
Source/WebCore/rendering/RenderTreeAsText.cpp
Source/WebCore/rendering/SimpleLineLayoutResolver.cpp
Source/WebCore/rendering/SimpleLineLayoutResolver.h
Source/WebCore/rendering/line/LineLayoutInterfaceTextBoxes.cpp
Source/WebCore/rendering/line/LineLayoutInterfaceTextBoxes.h

index 0ac2f70..1ab83e8 100644 (file)
@@ -1,3 +1,24 @@
+2019-09-16  Antti Koivisto  <antti@apple.com>
+
+        Eliminate separate simple line layout path from TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=201760
+
+        Reviewed by Zalan Bujtas.
+
+        This patch makes simple and complex line layout path results from TextIterator match, causing some whitespace changes.
+
+        * animations/lineheight-animation-expected.txt:
+        * animations/simultaneous-start-transform-expected.txt:
+        * animations/width-using-ems-expected.txt:
+        * compositing/shared-backing/overflow-scroll/absolute-in-stacking-relative-in-scroller-expected.txt:
+        * css3/filters/backdrop/backdrop-filter-does-not-size-properly-absolute-expected.txt:
+        * fast/events/window-events-bubble-expected.txt:
+        * fast/events/window-events-bubble2-expected.txt:
+        * fast/tokenizer/script_extra_close-expected.txt:
+        * legacy-animation-engine/animations/lineheight-animation-expected.txt:
+        * legacy-animation-engine/animations/simultaneous-start-transform-expected.txt:
+        * scrollingcoordinator/scrolling-tree/nested-absolute-in-overflow-expected.txt:
+
 2019-09-16  Andres Gonzalez  <andresg_22@apple.com>
 
         Expose misspelling ranges for editable content to accessibility clients.
index 39236b3..4172a8c 100644 (file)
@@ -1,3 +1,3 @@
-This test performs an animation of the line-height property. It tests whether or not we are properly getting the font-size.Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
+This test performs an animation of the line-height property. It tests whether or not we are properly getting the font-size. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
 PASS - "lineHeight" property for "box" element at 0.1s saw something close to: 10
 
index ac5be32..d9e8722 100644 (file)
@@ -1,4 +1,4 @@
-This test performs an animation of the transform property. It animates over 10 seconds. It takes 3 snapshots and expects each result to be within a specified range.PASS - "webkitTransform" property for "box1" element at 2s saw something close to: 0.309017,0.951057
+This test performs an animation of the transform property. It animates over 10 seconds. It takes 3 snapshots and expects each result to be within a specified range. PASS - "webkitTransform" property for "box1" element at 2s saw something close to: 0.309017,0.951057
 PASS - "webkitTransform" property for "box2" element at 2s saw something close to: 0.309017,0.951057
 PASS - "webkitTransform" property for "box1" and "box2" elements at 2s are close enough to each other
 PASS - "webkitTransform" property for "box1" element at 5s saw something close to: -1,0
index dfb737d..bcf6191 100644 (file)
@@ -1,3 +1,3 @@
-This test performs an animation of the width property using 'em' units. It tests whether or not we are properly getting the default font-size.Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
+This test performs an animation of the width property using 'em' units. It tests whether or not we are properly getting the default font-size. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
 PASS - "width" property for "box" element at 0.333s saw something close to: 133
 
index ec0d130..f880565 100644 (file)
@@ -1 +1 @@
-Test that stopPropagation() will not allow window events to bubble. Clicking on this should not fire window.onclick. This matches our old behavior and Firefox behavior.stopPropagation called. Test Passed.
+Test that stopPropagation() will not allow window events to bubble. Clicking on this should not fire window.onclick. This matches our old behavior and Firefox behavior. stopPropagation called. Test Passed.
index 98294e3..3a3e376 100644 (file)
@@ -1 +1 @@
-Tests that preventDefault() will still allow window events to bubble. Clicking here should fire window.onclick. This will match Firefox behavior.Window.onClick fired. Test Passed.
+Tests that preventDefault() will still allow window events to bubble. Clicking here should fire window.onclick. This will match Firefox behavior. Window.onClick fired. Test Passed.
index 42fa8d8..79eb9a6 100644 (file)
@@ -1 +1 @@
-TEST... PASSED. This text should show up.
+TEST...        PASSED. This text should show up.
index 9170d06..e4452c3 100644 (file)
@@ -1,3 +1,17 @@
+2019-09-16  Antti Koivisto  <antti@apple.com>
+
+    Eliminate separate simple line layout path from TextIterator
+    https://bugs.webkit.org/show_bug.cgi?id=201760
+
+    Reviewed by Zalan Bujtas.
+
+    * web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015-expected.txt:
+    * web-platform-tests/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016-expected.txt:
+    * web-platform-tests/innerText/getter-expected.txt:
+
+    Two '\t' subtests flip to FAIL because this was only supported on TextIterator simple line layout path.
+    This can now be fixed correctly for both paths.
+
 2019-09-15  Chris Dumez  <cdumez@apple.com>
 
         Re-sync HTML web-platform-tests from upstream
index b37b835..703ff4a 100644 (file)
@@ -7,7 +7,7 @@ PASS Trailing whitespace removed ("<div>abc ")
 PASS Internal whitespace compressed ("<div>abc  def") 
 PASS \n converted to space ("<div>abc\ndef") 
 PASS \r converted to space ("<div>abc\rdef") 
-PASS \t converted to space ("<div>abc\tdef") 
+FAIL \t converted to space ("<div>abc\tdef") assert_equals: expected "abc def" but got "abc\tdef"
 FAIL Trailing whitespace before hard line break removed ("<div>abc <br>def") assert_equals: expected "abc\ndef" but got "abc \ndef"
 PASS Leading whitespace after hard line break removed ("<div>abc<br> def") 
 PASS Leading whitespace preserved ("<pre> abc") 
@@ -32,9 +32,9 @@ PASS \t preserved ("<span style='white-space:pre'>abc\tdef")
 PASS Leading whitespace removed ("<div style='white-space:pre-line'> abc") 
 PASS Trailing whitespace removed ("<div style='white-space:pre-line'>abc ") 
 PASS Internal whitespace collapsed ("<div style='white-space:pre-line'>abc  def") 
-FAIL \n preserved ("<div style='white-space:pre-line'>abc\ndef") assert_equals: expected "abc\ndef" but got "abcdef"
-FAIL \r converted to newline ("<div style='white-space:pre-line'>abc\rdef") assert_equals: expected "abc\ndef" but got "abcdef"
-PASS \t converted to space ("<div style='white-space:pre-line'>abc\tdef") 
+FAIL \n preserved ("<div style='white-space:pre-line'>abc\ndef") assert_equals: expected "abc\ndef" but got "abc def"
+FAIL \r converted to newline ("<div style='white-space:pre-line'>abc\rdef") assert_equals: expected "abc\ndef" but got "abc def"
+FAIL \t converted to space ("<div style='white-space:pre-line'>abc\tdef") assert_equals: expected "abc def" but got "abc\tdef"
 PASS Whitespace collapses across element boundaries ("<div><span>abc </span> def") 
 PASS Whitespace collapses across element boundaries ("<div><span>abc </span><span></span> def") 
 FAIL Whitespace collapses across element boundaries ("<div><span>abc </span><span style='white-space:pre'></span> def") assert_equals: expected "abc def" but got "abc  def"
@@ -151,7 +151,7 @@ FAIL One blank line between <p>s, ignoring empty <p>s ("<div><p>abc<p></p><p></p
 FAIL Invisible <p> doesn't induce extra line breaks ("<div style='visibility:hidden'><p><span style='visibility:visible'>abc</span></p>\n<div style='visibility:visible'>def</div>") assert_equals: expected "abc\ndef" but got "abc\n\ndef\n"
 FAIL No blank lines around <div> with margin ("<div>abc<div style='margin:2em'>def") assert_equals: expected "abc\ndef" but got "abc\ndef\n"
 PASS No newlines at display:inline-block boundary ("<div>123<span style='display:inline-block'>abc</span>def") 
-FAIL Leading/trailing space removal at display:inline-block boundary ("<div>123<span style='display:inline-block'> abc </span>def") assert_equals: expected "123abcdef" but got "123abc def"
+FAIL Leading/trailing space removal at display:inline-block boundary ("<div>123<span style='display:inline-block'> abc </span>def") assert_equals: expected "123abcdef" but got "123 abc def"
 FAIL Blank lines around <p> even without margin ("<div>123<p style='margin:0px'>abc</p>def") assert_equals: expected "123\n\nabc\n\ndef" but got "123\nabc\ndef"
 FAIL No blank lines around <h1> ("<div>123<h1>abc</h1>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
 FAIL No blank lines around <h2> ("<div>123<h2>abc</h2>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
index 046d6f5..d07ffae 100644 (file)
@@ -7,7 +7,7 @@ PASS Trailing whitespace removed ("<div>abc ")
 PASS Internal whitespace compressed ("<div>abc  def") 
 PASS \n converted to space ("<div>abc\ndef") 
 PASS \r converted to space ("<div>abc\rdef") 
-PASS \t converted to space ("<div>abc\tdef") 
+FAIL \t converted to space ("<div>abc\tdef") assert_equals: expected "abc def" but got "abc\tdef"
 FAIL Trailing whitespace before hard line break removed ("<div>abc <br>def") assert_equals: expected "abc\ndef" but got "abc \ndef"
 PASS Leading whitespace preserved ("<pre> abc") 
 PASS Trailing whitespace preserved ("<pre>abc ") 
@@ -31,9 +31,9 @@ PASS \t preserved ("<span style='white-space:pre'>abc\tdef")
 PASS Leading whitespace removed ("<div style='white-space:pre-line'> abc") 
 PASS Trailing whitespace removed ("<div style='white-space:pre-line'>abc ") 
 PASS Internal whitespace collapsed ("<div style='white-space:pre-line'>abc  def") 
-FAIL \n preserved ("<div style='white-space:pre-line'>abc\ndef") assert_equals: expected "abc\ndef" but got "abcdef"
-FAIL \r converted to newline ("<div style='white-space:pre-line'>abc\rdef") assert_equals: expected "abc\ndef" but got "abcdef"
-PASS \t converted to space ("<div style='white-space:pre-line'>abc\tdef") 
+FAIL \n preserved ("<div style='white-space:pre-line'>abc\ndef") assert_equals: expected "abc\ndef" but got "abc def"
+FAIL \r converted to newline ("<div style='white-space:pre-line'>abc\rdef") assert_equals: expected "abc\ndef" but got "abc def"
+FAIL \t converted to space ("<div style='white-space:pre-line'>abc\tdef") assert_equals: expected "abc def" but got "abc\tdef"
 PASS Whitespace collapses across element boundaries ("<div><span>abc </span> def") 
 PASS Whitespace collapses across element boundaries ("<div><span>abc </span><span></span> def") 
 FAIL Whitespace collapses across element boundaries ("<div><span>abc </span><span style='white-space:pre'></span> def") assert_equals: expected "abc def" but got "abc  def"
@@ -135,7 +135,7 @@ FAIL One blank line between <p>s, ignoring empty <p>s ("<div><p>abc<p></p><p></p
 FAIL Invisible <p> doesn't induce extra line breaks ("<div style='visibility:hidden'><p><span style='visibility:visible'>abc</span></p>\n<div style='visibility:visible'>def</div>") assert_equals: expected "abc\ndef" but got "abc\n\ndef\n"
 FAIL No blank lines around <div> with margin ("<div>abc<div style='margin:2em'>def") assert_equals: expected "abc\ndef" but got "abc\ndef\n"
 PASS No newlines at display:inline-block boundary ("<div>123<span style='display:inline-block'>abc</span>def") 
-FAIL Leading/trailing space removal at display:inline-block boundary ("<div>123<span style='display:inline-block'> abc </span>def") assert_equals: expected "123abcdef" but got "123abc def"
+FAIL Leading/trailing space removal at display:inline-block boundary ("<div>123<span style='display:inline-block'> abc </span>def") assert_equals: expected "123abcdef" but got "123 abc def"
 FAIL Blank lines around <p> even without margin ("<div>123<p style='margin:0px'>abc</p>def") assert_equals: expected "123\n\nabc\n\ndef" but got "123\nabc\ndef"
 FAIL No blank lines around <h1> ("<div>123<h1>abc</h1>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
 FAIL No blank lines around <h2> ("<div>123<h2>abc</h2>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
index 39236b3..4172a8c 100644 (file)
@@ -1,3 +1,3 @@
-This test performs an animation of the line-height property. It tests whether or not we are properly getting the font-size.Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
+This test performs an animation of the line-height property. It tests whether or not we are properly getting the font-size. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
 PASS - "lineHeight" property for "box" element at 0.1s saw something close to: 10
 
index ac5be32..d9e8722 100644 (file)
@@ -1,4 +1,4 @@
-This test performs an animation of the transform property. It animates over 10 seconds. It takes 3 snapshots and expects each result to be within a specified range.PASS - "webkitTransform" property for "box1" element at 2s saw something close to: 0.309017,0.951057
+This test performs an animation of the transform property. It animates over 10 seconds. It takes 3 snapshots and expects each result to be within a specified range. PASS - "webkitTransform" property for "box1" element at 2s saw something close to: 0.309017,0.951057
 PASS - "webkitTransform" property for "box2" element at 2s saw something close to: 0.309017,0.951057
 PASS - "webkitTransform" property for "box1" and "box2" elements at 2s are close enough to each other
 PASS - "webkitTransform" property for "box1" element at 5s saw something close to: -1,0
index dfb737d..bcf6191 100644 (file)
@@ -1,3 +1,3 @@
-This test performs an animation of the width property using 'em' units. It tests whether or not we are properly getting the default font-size.Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
+This test performs an animation of the width property using 'em' units. It tests whether or not we are properly getting the default font-size. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text. Here is some text.
 PASS - "width" property for "box" element at 0.333s saw something close to: 133
 
index a00fd0d..6ae2411 100644 (file)
@@ -1,3 +1,81 @@
+2019-09-16  Antti Koivisto  <antti@apple.com>
+
+        Eliminate separate simple line layout path from TextIterator
+        https://bugs.webkit.org/show_bug.cgi?id=201760
+
+        Reviewed by Zalan Bujtas.
+
+        Use the new line layout iterator to implement linebox traversal in TextIterator.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * editing/TextIterator.cpp:
+        (WebCore::TextIterator::advance):
+        (WebCore::TextIterator::handleTextNode):
+        (WebCore::TextIterator::handleTextBox):
+
+        InlineTextBox* -> LineLayoutInterface::TextBoxIterator
+        Delete the seperate simple line layout path.
+
+        (WebCore::TextIterator::handleTextNodeFirstLetter):
+        (WebCore::TextIterator::emitCharacter):
+        (WebCore::TextIterator::emitText):
+        * editing/TextIterator.h:
+        * rendering/RenderTreeAsText.cpp:
+        (WebCore::RenderTreeAsText::writeRenderObject):
+        (WebCore::write):
+        * rendering/SimpleLineLayoutResolver.cpp:
+        (WebCore::SimpleLineLayout::RunResolver::Iterator::Iterator):
+        (WebCore::SimpleLineLayout::RunResolver::Iterator::advanceLines):
+        * rendering/SimpleLineLayoutResolver.h:
+        (WebCore::SimpleLineLayout::RunResolver::Iterator::resolver const):
+        (WebCore::SimpleLineLayout::RunResolver::Iterator::inQuirksMode const):
+        (WebCore::SimpleLineLayout::RunResolver::Iterator::operator== const):
+        (WebCore::SimpleLineLayout::RunResolver::Iterator::simpleRun const):
+
+        Make RunResolver::Iterator copyable (so TextBoxIterator becomes copyable too).
+
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::findNextTextFragment):
+        * rendering/line/LineLayoutInterfaceTextBoxes.cpp:
+        (WebCore::LineLayoutInterface::TextBox::rect const):
+        (WebCore::LineLayoutInterface::TextBox::logicalRect const):
+        (WebCore::LineLayoutInterface::TextBox::hasHyphen const):
+        (WebCore::LineLayoutInterface::TextBox::isLeftToRightDirection const):
+        (WebCore::LineLayoutInterface::TextBox::dirOverride const):
+        (WebCore::LineLayoutInterface::TextBox::text const):
+        (WebCore::LineLayoutInterface::TextBox::localStartOffset const):
+        (WebCore::LineLayoutInterface::TextBox::localEndOffset const):
+        (WebCore::LineLayoutInterface::TextBox::length const):
+
+        Add offset and length functions.
+
+        (WebCore::LineLayoutInterface::TextBox::iterator const):
+        (WebCore::LineLayoutInterface::TextBoxIterator::TextBoxIterator):
+        (WebCore::LineLayoutInterface::TextBoxIterator::traverseNext):
+        (WebCore::LineLayoutInterface::TextBoxIterator::operator== const):
+        (WebCore::LineLayoutInterface::TextBoxIterator::atEnd const):
+        (WebCore::LineLayoutInterface::Provider::firstTextBoxFor):
+        (WebCore::LineLayoutInterface::Provider::textBoxRangeFor):
+        (WebCore::LineLayoutInterface::Provider::iteratorForInlineTextBox):
+
+        Add Provider class for making iterators. It constructs and keeps SimpleLineLayout::Resolvers alive during traversal as needed.
+
+        * rendering/line/LineLayoutInterfaceTextBoxes.h:
+        (WebCore::LineLayoutInterface::TextBoxIterator::TextBoxIterator):
+        (WebCore::LineLayoutInterface::TextBoxIterator::operator bool const):
+        (WebCore::LineLayoutInterface::TextBoxIterator::operator== const):
+        (WebCore::LineLayoutInterface::TextBoxIterator::operator!= const):
+        (WebCore::LineLayoutInterface::TextBoxIterator::operator* const):
+        (WebCore::LineLayoutInterface::TextBoxIterator::operator-> const):
+
+        Make TextBoxIterator privately inherit TextBox. This way we don't need to construct temporaries and can easily implement operator->.
+
+        (WebCore::LineLayoutInterface::TextBoxRange::TextBoxRange):
+        (WebCore::LineLayoutInterface::TextBoxRange::begin const):
+        (WebCore::LineLayoutInterface::TextBoxRange::end const):
+
+        Use separate end() type of C++17 ranges.
+
 2019-09-16  Andres Gonzalez  <andresg_22@apple.com>
 
         Expose misspelling ranges for editable content to accessibility clients.
index 30d0929..fd0b533 100644 (file)
@@ -1303,7 +1303,10 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     rendering/SelectionRangeData.h
     rendering/SimpleLineLayout.h
     rendering/SimpleLineLayoutCoverage.h
+    rendering/SimpleLineLayoutFlowContents.h
+    rendering/SimpleLineLayoutResolver.h
 
+    rendering/line/LineLayoutInterfaceTextBoxes.h
     rendering/line/LineWidth.h
     rendering/line/TrailingObjects.h
 
index cd7889d..deeddb5 100644 (file)
                5824ABA71AE81384009074B7 /* RubyTextElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 5824ABA51AE81384009074B7 /* RubyTextElement.h */; };
                582CB0531A78A14B00AFFCC4 /* SimpleLineLayoutTextFragmentIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 582CB0521A78A14B00AFFCC4 /* SimpleLineLayoutTextFragmentIterator.h */; };
                582DE3251C30C85400BE02A8 /* TextDecorationPainter.h in Headers */ = {isa = PBXBuildFile; fileRef = 582DE3231C30C85400BE02A8 /* TextDecorationPainter.h */; };
-               585D6E041A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h in Headers */ = {isa = PBXBuildFile; fileRef = 585D6E021A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h */; };
+               585D6E041A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h in Headers */ = {isa = PBXBuildFile; fileRef = 585D6E021A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h */; settings = {ATTRIBUTES = (Private, ); }; };
                589556ED18D4A44000764B03 /* BorderEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 589556EC18D4A44000764B03 /* BorderEdge.h */; };
                58B2F9F42232D45300938D63 /* ResizeObservation.h in Headers */ = {isa = PBXBuildFile; fileRef = 58B2F9F32232D43F00938D63 /* ResizeObservation.h */; };
                58B2F9F52232D45800938D63 /* ResizeObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 58B2F9EC2232D43B00938D63 /* ResizeObserver.h */; };
                E47C39331FE6E10800BBBC6B /* RenderTreeBuilderMultiColumn.h in Headers */ = {isa = PBXBuildFile; fileRef = E47C39271FE6E0DC00BBBC6B /* RenderTreeBuilderMultiColumn.h */; };
                E47E276516036ED200EE2AFB /* ExtensionStyleSheets.h in Headers */ = {isa = PBXBuildFile; fileRef = E47E276416036ED200EE2AFB /* ExtensionStyleSheets.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E48137B91DB3B526005C59BF /* StyleValidity.h in Headers */ = {isa = PBXBuildFile; fileRef = E48137B81DB3B526005C59BF /* StyleValidity.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               E484A33E23055325009ADE6A /* LineLayoutInterfaceTextBoxes.h in Headers */ = {isa = PBXBuildFile; fileRef = E484A33B23055303009ADE6A /* LineLayoutInterfaceTextBoxes.h */; };
+               E484A33E23055325009ADE6A /* LineLayoutInterfaceTextBoxes.h in Headers */ = {isa = PBXBuildFile; fileRef = E484A33B23055303009ADE6A /* LineLayoutInterfaceTextBoxes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E48944A3180B57D800F165D8 /* SimpleLineLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = E48944A1180B57D800F165D8 /* SimpleLineLayout.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E4916FF7195DF6A0005AB349 /* LayerFlushThrottleState.h in Headers */ = {isa = PBXBuildFile; fileRef = E4916FF6195DF6A0005AB349 /* LayerFlushThrottleState.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E4946EAF156E64DD00D3297F /* StyleRuleImport.h in Headers */ = {isa = PBXBuildFile; fileRef = E4946EAD156E64DD00D3297F /* StyleRuleImport.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E4E8B4EC216B79E500B8834D /* SystemFontDatabaseCoreText.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E8B4EA216B79E500B8834D /* SystemFontDatabaseCoreText.h */; };
                E4E8B4F5216B956500B8834D /* FontCascadeDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E8B4F2216B8B6000B8834D /* FontCascadeDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E4E94D6122FF158A00DD191F /* ComplexLineLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = E4A1AC7822FAFD500017B75B /* ComplexLineLayout.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               E4E9B1191810916F003ACCDF /* SimpleLineLayoutResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E9B1181810916F003ACCDF /* SimpleLineLayoutResolver.h */; };
+               E4E9B1191810916F003ACCDF /* SimpleLineLayoutResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E9B1181810916F003ACCDF /* SimpleLineLayoutResolver.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E4E9B11D1814569C003ACCDF /* SimpleLineLayoutFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = E4E9B11C1814569C003ACCDF /* SimpleLineLayoutFunctions.h */; };
                E4F9EEF3156DA00700D23E7E /* StyleSheetContents.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F9EEF1156D84C400D23E7E /* StyleSheetContents.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E516699120FF9918009D2C27 /* ListButtonArrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E516698F20FF9916009D2C27 /* ListButtonArrow@2x.png */; };
index a1a3903..f41e102 100644 (file)
@@ -474,8 +474,8 @@ void TextIterator::advance()
 
     if (!m_textBox && m_remainingTextBox) {
         m_textBox = m_remainingTextBox;
-        m_remainingTextBox = nullptr;
-        m_firstLetterText = nullptr;
+        m_remainingTextBox = { };
+        m_firstLetterText = { };
         m_offset = 0;
     }
     // handle remembered text box
@@ -574,25 +574,6 @@ static bool hasVisibleTextNode(RenderText& renderer)
     return false;
 }
 
-static unsigned textNodeOffsetInFlow(const Text& firstTextNodeInRange)
-{
-    // Calculate the text offset for simple lines.
-    RenderObject* renderer = firstTextNodeInRange.renderer();
-    if (!renderer)
-        return 0;
-    unsigned textOffset = 0;
-    for (renderer = renderer->previousSibling(); renderer; renderer = renderer->previousSibling()) {
-        if (is<RenderText>(renderer))
-            textOffset += downcast<RenderText>(renderer)->text().length();
-    }
-    return textOffset;
-}
-
-static bool isNewLineOrTabCharacter(UChar character)
-{
-    return character == '\n' || character == '\t';
-}
-
 bool TextIterator::handleTextNode()
 {
     Text& textNode = downcast<Text>(*m_node);
@@ -617,7 +598,7 @@ bool TextIterator::handleTextNode()
                 String firstLetter = m_firstLetterText->text();
                 emitText(textNode, *m_firstLetterText, m_offset, m_offset + firstLetter.length());
                 m_firstLetterText = nullptr;
-                m_textBox = nullptr;
+                m_textBox = { };
                 return false;
             }
         }
@@ -634,102 +615,13 @@ bool TextIterator::handleTextNode()
         return true;
     }
 
-    if (const auto* layout = renderer.simpleLineLayout()) {
-        if (renderer.style().visibility() != Visibility::Visible && !(m_behavior & TextIteratorIgnoresStyleVisibility))
-            return true;
-        ASSERT(renderer.parent());
-        ASSERT(is<RenderBlockFlow>(*renderer.parent()));
-        const auto& blockFlow = downcast<RenderBlockFlow>(*renderer.parent());
-        // Use the simple layout runs to iterate over the text content.
-        bool isNewTextNode = m_previousSimpleTextNodeInFlow && m_previousSimpleTextNodeInFlow != &textNode;
-        // Simple line layout run positions are all absolute to the parent flow.
-        // Offsetting is required when multiple renderers are present.
-        m_accumulatedSimpleTextLengthInFlow += isNewTextNode ? m_previousSimpleTextNodeInFlow->renderer()->text().length() : 0;
-        m_previousSimpleTextNodeInFlow = &textNode;
-
-        unsigned endPosition = (m_node == m_endContainer) ? static_cast<unsigned>(m_endOffset) : rendererText.length();
-        if (!m_flowRunResolverCache || &m_flowRunResolverCache->flow() != &blockFlow) {
-            m_accumulatedSimpleTextLengthInFlow = m_flowRunResolverCache ? 0 : textNodeOffsetInFlow(textNode);
-            m_flowRunResolverCache = makeUnique<SimpleLineLayout::RunResolver>(blockFlow, *layout);
-        }
-        // Skip to m_offset position.
-        auto range = m_flowRunResolverCache->rangeForRenderer(renderer);
-        auto it = range.begin();
-        auto end = range.end();
-        auto startPosition = static_cast<unsigned>(m_offset) + m_accumulatedSimpleTextLengthInFlow;
-        while (it != end && (*it).end() <= startPosition)
-            ++it;
-        if (m_nextRunNeedsWhitespace && rendererText[m_offset - 1] == '\n') {
-            emitCharacter(' ', textNode, nullptr, m_offset, m_offset + 1);
-            return it == end;
-        }
-        if (it == end) {
-            // Collapsed trailing whitespace.
-            m_offset = endPosition;
-            m_lastTextNodeEndedWithCollapsedSpace = true;
-            return true;
-        }
-        if (m_nextRunNeedsWhitespace) {
-            emitCharacter(' ', textNode, nullptr, m_offset, m_offset + 1);
-            return false;
-        }
-        // If the position we are looking for is to the left of the renderer's first run, it could mean that
-        // the runs and the renderers are out of sync (e.g. we skipped a renderer in between).
-        // Better bail out at this point.
-        auto run = *it;
-        if (run.start() > startPosition) {
-            ASSERT(m_flowRunResolverCache);
-            if (&(rendererForPosition(m_flowRunResolverCache->flowContents(), startPosition)) != &renderer) {
-                ASSERT_NOT_REACHED();
-                return true;
-            }
-        }
-        ASSERT(run.end() - run.start() <= rendererText.length());
-        // contentStart skips leading whitespace.
-        unsigned contentStart = std::max<unsigned>(m_offset, run.start() - m_accumulatedSimpleTextLengthInFlow);
-        unsigned contentEnd = std::min(endPosition, run.end() - m_accumulatedSimpleTextLengthInFlow);
-        ASSERT_WITH_SECURITY_IMPLICATION(contentStart <= contentEnd);
-        // Check if whitespace adjustment is needed when crossing renderer boundary.
-        if (isNewTextNode) {
-            bool lastCharacterIsNotWhitespace = m_lastCharacter && !renderer.style().isCollapsibleWhiteSpace(m_lastCharacter);
-            bool addTrailingWhitespaceForPrevious = m_lastTextNodeEndedWithCollapsedSpace && lastCharacterIsNotWhitespace;
-            bool leadingWhitespaceIsNeededForCurrent = contentStart > static_cast<unsigned>(m_offset) && lastCharacterIsNotWhitespace;
-            if (addTrailingWhitespaceForPrevious || leadingWhitespaceIsNeededForCurrent) {
-                emitCharacter(' ', textNode, nullptr, m_offset, m_offset + 1);
-                return false;
-            }
-        }
-        // \n \t single whitespace characters need replacing so that the new line/tab characters don't show up.
-        unsigned stopPosition = contentStart;
-        while (stopPosition < contentEnd && !isNewLineOrTabCharacter(rendererText[stopPosition]))
-            ++stopPosition;
-        // Emit the text up to the new line/tab character.
-        if (stopPosition < contentEnd) {
-            if (stopPosition == contentStart) {
-                emitCharacter(' ', textNode, nullptr, contentStart, contentStart + 1);
-                m_offset = contentStart + 1;
-                return false;
-            }
-            emitText(textNode, renderer, contentStart, stopPosition);
-            m_offset = stopPosition + 1;
-            m_nextRunNeedsWhitespace = true;
-            return false;
-        }
-        emitText(textNode, renderer, contentStart, contentEnd);
-        // When line ending with collapsed whitespace is present, we need to carry over one whitespace: foo(end of line)bar -> foo bar (otherwise we would end up with foobar).
-        m_nextRunNeedsWhitespace = run.isEndOfLine() && contentEnd < endPosition && renderer.style().isCollapsibleWhiteSpace(rendererText[contentEnd]);
-        m_offset = contentEnd;
-        return static_cast<unsigned>(m_offset) == endPosition;
-    }
-
-    if (renderer.firstTextBox())
-        m_textBox = renderer.firstTextBox();
+    m_textBox = m_lineLayoutProvider.firstTextBoxFor(renderer);
 
     bool shouldHandleFirstLetter = !m_handledFirstLetter && is<RenderTextFragment>(renderer) && !m_offset;
     if (shouldHandleFirstLetter)
         handleTextNodeFirstLetter(downcast<RenderTextFragment>(renderer));
 
-    if (!renderer.firstTextBox() && rendererText.length() && !shouldHandleFirstLetter) {
+    if (!m_textBox && rendererText.length() && !shouldHandleFirstLetter) {
         if (renderer.style().visibility() != Visibility::Visible && !(m_behavior & TextIteratorIgnoresStyleVisibility))
             return false;
         m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space
@@ -744,7 +636,7 @@ bool TextIterator::handleTextNode()
             m_sortedTextBoxes.append(textBox);
         std::sort(m_sortedTextBoxes.begin(), m_sortedTextBoxes.end(), InlineTextBox::compareByStart);
         m_sortedTextBoxesPosition = 0;
-        m_textBox = m_sortedTextBoxes.isEmpty() ? nullptr : m_sortedTextBoxes[0];
+        m_textBox = m_lineLayoutProvider.iteratorForInlineTextBox(m_sortedTextBoxes.isEmpty() ? nullptr : m_sortedTextBoxes[0]);
     }
 
     handleTextBox();
@@ -757,18 +649,25 @@ void TextIterator::handleTextBox()
 
     auto& renderer = m_firstLetterText ? *m_firstLetterText : *textNode.renderer();
     if (renderer.style().visibility() != Visibility::Visible && !(m_behavior & TextIteratorIgnoresStyleVisibility)) {
-        m_textBox = nullptr;
+        m_textBox = { };
         return;
     }
+
+    auto firstTextBox = [&] {
+        if (renderer.containsReversedText())
+            return m_lineLayoutProvider.iteratorForInlineTextBox(m_sortedTextBoxes.isEmpty() ? nullptr : m_sortedTextBoxes[0]);
+
+        return m_lineLayoutProvider.firstTextBoxFor(renderer);
+    }();
+
     String rendererText = renderer.text();
     unsigned start = m_offset;
     unsigned end = (&textNode == m_endContainer) ? static_cast<unsigned>(m_endOffset) : UINT_MAX;
     while (m_textBox) {
-        unsigned textBoxStart = m_textBox->start();
+        unsigned textBoxStart = m_textBox->localStartOffset();
         unsigned runStart = std::max(textBoxStart, start);
 
         // Check for collapsed space at the start of this run.
-        InlineTextBox* firstTextBox = renderer.containsReversedText() ? (m_sortedTextBoxes.isEmpty() ? nullptr : m_sortedTextBoxes[0]) : renderer.firstTextBox();
         bool needSpace = m_lastTextNodeEndedWithCollapsedSpace || (m_textBox == firstTextBox && textBoxStart == runStart && runStart);
         if (needSpace && !renderer.style().isCollapsibleWhiteSpace(m_lastCharacter) && m_lastCharacter) {
             if (m_lastTextNode == &textNode && runStart && rendererText[runStart - 1] == ' ') {
@@ -780,17 +679,19 @@ void TextIterator::handleTextBox()
                 emitCharacter(' ', textNode, nullptr, runStart, runStart);
             return;
         }
-        unsigned textBoxEnd = textBoxStart + m_textBox->len();
+        unsigned textBoxEnd = textBoxStart + m_textBox->length();
         unsigned runEnd = std::min(textBoxEnd, end);
         
         // Determine what the next text box will be, but don't advance yet
-        InlineTextBox* nextTextBox = nullptr;
+        LineLayoutInterface::TextBoxIterator nextTextBox;
         if (renderer.containsReversedText()) {
+            // FIXME: Handle reversed text in the line layout iterator.
             if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size())
-                nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1];
-        } else 
-            nextTextBox = m_textBox->nextTextBox();
-        ASSERT(!nextTextBox || &nextTextBox->renderer() == &renderer);
+                nextTextBox = m_lineLayoutProvider.iteratorForInlineTextBox(m_sortedTextBoxes[m_sortedTextBoxesPosition + 1]);
+        } else {
+            nextTextBox = m_textBox;
+            ++nextTextBox;
+        }
 
         if (runStart < runEnd) {
             // Handle either a single newline character (which becomes a space),
@@ -817,7 +718,7 @@ void TextIterator::handleTextBox()
                 return;
 
             // Advance and return
-            unsigned nextRunStart = nextTextBox ? nextTextBox->start() : rendererText.length();
+            unsigned nextRunStart = nextTextBox ? nextTextBox->localStartOffset() : rendererText.length();
             if (nextRunStart > runEnd)
                 m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end
             m_textBox = nextTextBox;
@@ -832,8 +733,8 @@ void TextIterator::handleTextBox()
     }
     if (!m_textBox && m_remainingTextBox) {
         m_textBox = m_remainingTextBox;
-        m_remainingTextBox = nullptr;
-        m_firstLetterText = nullptr;
+        m_remainingTextBox = { };
+        m_firstLetterText = { };
         m_offset = 0;
         handleTextBox();
     }
@@ -856,7 +757,7 @@ void TextIterator::handleTextNodeFirstLetter(RenderTextFragment& renderer)
         if (auto* firstLetterText = firstRenderTextInFirstLetter(firstLetter)) {
             m_handledFirstLetter = true;
             m_remainingTextBox = m_textBox;
-            m_textBox = firstLetterText->firstTextBox();
+            m_textBox = m_lineLayoutProvider.firstTextBoxFor(*firstLetterText);
             m_sortedTextBoxes.clear();
             m_firstLetterText = firstLetterText;
         }
@@ -1222,7 +1123,6 @@ void TextIterator::emitCharacter(UChar character, Node& characterNode, Node* off
     m_text = m_copyableText.text();
     m_lastCharacter = character;
     m_lastTextNodeEndedWithCollapsedSpace = false;
-    m_nextRunNeedsWhitespace = false;
 }
 
 void TextIterator::emitText(Text& textNode, RenderText& renderer, int textStartOffset, int textEndOffset)
@@ -1247,7 +1147,6 @@ void TextIterator::emitText(Text& textNode, RenderText& renderer, int textStartO
     m_text = m_copyableText.text();
 
     m_lastTextNodeEndedWithCollapsedSpace = false;
-    m_nextRunNeedsWhitespace = false;
     m_hasEmitted = true;
 }
 
index 1f4fddf..ebc2532 100644 (file)
@@ -28,6 +28,7 @@
 // FIXME: Move each iterator class into a separate header file.
 
 #include "FindOptions.h"
+#include "LineLayoutInterfaceTextBoxes.h"
 #include "Range.h"
 #include "TextIteratorBehavior.h"
 #include <wtf/Vector.h>
@@ -167,10 +168,10 @@ private:
 
     // Used when there is still some pending text from the current node; when these are false and null, we go back to normal iterating.
     Node* m_nodeForAdditionalNewline { nullptr };
-    InlineTextBox* m_textBox { nullptr };
+    LineLayoutInterface::TextBoxIterator m_textBox;
 
     // Used when iterating over :first-letter text to save pointer to remaining text box.
-    InlineTextBox* m_remainingTextBox { nullptr };
+    LineLayoutInterface::TextBoxIterator m_remainingTextBox;
 
     // Used to point to RenderText object for :first-letter.
     RenderText* m_firstLetterText { nullptr };
@@ -180,11 +181,7 @@ private:
     bool m_lastTextNodeEndedWithCollapsedSpace { false };
     UChar m_lastCharacter { 0 };
 
-    // Used to do simple line layout run logic.
-    bool m_nextRunNeedsWhitespace { false };
-    unsigned m_accumulatedSimpleTextLengthInFlow { 0 };
-    Text* m_previousSimpleTextNodeInFlow { nullptr };
-    std::unique_ptr<SimpleLineLayout::RunResolver> m_flowRunResolverCache;
+    LineLayoutInterface::Provider m_lineLayoutProvider;
 
     // Used when text boxes are out of order (Hebrew/Arabic with embedded LTR text)
     Vector<InlineTextBox*> m_sortedTextBoxes;
index a07c4d0..8d4ed92 100644 (file)
@@ -202,8 +202,8 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o,
         // many test results.
         const RenderText& text = downcast<RenderText>(o);
         r = IntRect(text.firstRunLocation(), text.linesBoundingBox().size());
-        auto textBoxes = LineLayoutInterface::textBoxes(text);
-        if (textBoxes.begin() == textBoxes.end())
+        LineLayoutInterface::Provider lineLayoutProvider;
+        if (!lineLayoutProvider.firstTextBoxFor(text))
             adjustForTableCells = false;
     } else if (o.isBR()) {
         const RenderLineBreak& br = downcast<RenderLineBreak>(o);
@@ -549,8 +549,9 @@ void write(TextStream& ts, const RenderObject& o, OptionSet<RenderAsTextFlag> be
     TextStream::IndentScope indentScope(ts);
 
     if (is<RenderText>(o)) {
+        LineLayoutInterface::Provider lineLayoutProvider;
         auto& text = downcast<RenderText>(o);
-        for (auto textBox : LineLayoutInterface::textBoxes(text)) {
+        for (auto& textBox : lineLayoutProvider.textBoxRangeFor(text)) {
             ts << indent;
             writeTextBox(ts, text, textBox);
         }
index 00f0381..d21d962 100644 (file)
@@ -113,7 +113,7 @@ unsigned RunResolver::Run::localEnd() const
 }
 
 RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex, unsigned lineIndex)
-    : m_resolver(resolver)
+    : m_resolver(&resolver)
     , m_runIndex(runIndex)
     , m_lineIndex(lineIndex)
 {
@@ -129,8 +129,8 @@ RunResolver::Iterator& RunResolver::Iterator::advance()
 
 RunResolver::Iterator& RunResolver::Iterator::advanceLines(unsigned lineCount)
 {
-    unsigned runCount = m_resolver.m_layout.runCount();
-    if (runCount == m_resolver.m_layout.lineCount()) {
+    unsigned runCount = resolver().m_layout.runCount();
+    if (runCount == resolver().m_layout.lineCount()) {
         m_runIndex = std::min(runCount, m_runIndex + lineCount);
         m_lineIndex = m_runIndex;
         return *this;
index 4559260..6ab7031 100644 (file)
@@ -94,10 +94,10 @@ public:
         unsigned lineIndex() const { return m_lineIndex; }
         Iterator& advance();
         Iterator& advanceLines(unsigned);
-        const RunResolver& resolver() const { return m_resolver; }
-        bool inQuirksMode() const { return m_resolver.m_inQuirksMode; }
+        const RunResolver& resolver() const { return *m_resolver; }
+        bool inQuirksMode() const { return resolver().m_inQuirksMode; }
 
-        const RunResolver& m_resolver;
+        const RunResolver* m_resolver;
         unsigned m_runIndex;
         unsigned m_lineIndex;
     };
@@ -238,7 +238,7 @@ inline RunResolver::Iterator& RunResolver::Iterator::operator--()
 
 inline bool RunResolver::Iterator::operator==(const Iterator& other) const
 {
-    ASSERT(&m_resolver == &other.m_resolver);
+    ASSERT(m_resolver == other.m_resolver);
     return m_runIndex == other.m_runIndex;
 }
 
@@ -254,7 +254,7 @@ inline RunResolver::Run RunResolver::Iterator::operator*() const
 
 inline const SimpleLineLayout::Run& RunResolver::Iterator::simpleRun() const
 {
-    return m_resolver.m_layout.runAt(m_runIndex);
+    return resolver().m_layout.runAt(m_runIndex);
 }
 
 inline RunResolver::Iterator RunResolver::begin() const
index daa863b..180c0ee 100644 (file)
@@ -35,46 +35,46 @@ namespace LineLayoutInterface {
 
 FloatRect TextBox::rect() const
 {
-    auto simple = [](const SimpleLineLayout::RunResolver::Iterator simpleLineIterator) {
-        return (*simpleLineIterator).rect();
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).rect();
     };
 
     auto complex = [](const InlineTextBox* inlineTextBox) {
         return inlineTextBox->frameRect();
     };
 
-    return WTF::switchOn(m_iterator.m_pathVariant, simple, complex);
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
 }
 
 FloatRect TextBox::logicalRect() const
 {
-    auto simple = [](const SimpleLineLayout::RunResolver::Iterator simpleLineIterator) {
-        return (*simpleLineIterator).rect();
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).rect();
     };
 
     auto complex = [](const InlineTextBox* inlineTextBox) {
         return inlineTextBox->logicalFrameRect();
     };
 
-    return WTF::switchOn(m_iterator.m_pathVariant, simple, complex);
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
 }
 
 bool TextBox::hasHyphen() const
 {
-    auto simple = [](const SimpleLineLayout::RunResolver::Iterator simpleLineIterator) {
-        return (*simpleLineIterator).hasHyphen();
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).hasHyphen();
     };
 
     auto complex = [](const InlineTextBox* inlineTextBox) {
         return inlineTextBox->hasHyphen();
     };
 
-    return WTF::switchOn(m_iterator.m_pathVariant, simple, complex);
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
 }
 
 bool TextBox::isLeftToRightDirection() const
 {
-    auto simple = [](const SimpleLineLayout::RunResolver::Iterator) {
+    auto simple = [](const TextBoxIterator::SimplePath&) {
         return true;
     };
 
@@ -82,12 +82,12 @@ bool TextBox::isLeftToRightDirection() const
         return inlineTextBox->isLeftToRightDirection();
     };
 
-    return WTF::switchOn(m_iterator.m_pathVariant, simple, complex);
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
 }
 
 bool TextBox::dirOverride() const
 {
-    auto simple = [](const SimpleLineLayout::RunResolver::Iterator) {
+    auto simple = [](const TextBoxIterator::SimplePath&) {
         return false;
     };
 
@@ -95,20 +95,64 @@ bool TextBox::dirOverride() const
         return inlineTextBox->dirOverride();
     };
 
-    return WTF::switchOn(m_iterator.m_pathVariant, simple, complex);
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
 }
 
 StringView TextBox::text() const
 {
-    auto simple = [](const SimpleLineLayout::RunResolver::Iterator simpleLineIterator) {
-        return (*simpleLineIterator).text();
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).text();
     };
 
     auto complex = [](const InlineTextBox* inlineTextBox) {
         return StringView(inlineTextBox->renderer().text()).substring(inlineTextBox->start(), inlineTextBox->len());
     };
 
-    return WTF::switchOn(m_iterator.m_pathVariant, simple, complex);
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
+}
+
+unsigned TextBox::localStartOffset() const
+{
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).localStart();
+    };
+
+    auto complex = [](const InlineTextBox* inlineTextBox) {
+        return inlineTextBox->start();
+    };
+
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
+}
+
+unsigned TextBox::localEndOffset() const
+{
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).localEnd();
+    };
+
+    auto complex = [](const InlineTextBox* inlineTextBox) {
+        return inlineTextBox->end();
+    };
+
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
+}
+
+unsigned TextBox::length() const
+{
+    auto simple = [](const TextBoxIterator::SimplePath& path) {
+        return (*path.iterator).end() - (*path.iterator).start();
+    };
+
+    auto complex = [](const InlineTextBox* inlineTextBox) {
+        return inlineTextBox->len();
+    };
+
+    return WTF::switchOn(iterator().m_pathVariant, simple, complex);
+}
+
+inline const TextBoxIterator& TextBox::iterator() const
+{
+    return static_cast<const TextBoxIterator&>(*this);
 }
 
 TextBoxIterator::TextBoxIterator(const InlineTextBox* inlineTextBox)
@@ -116,15 +160,15 @@ TextBoxIterator::TextBoxIterator(const InlineTextBox* inlineTextBox)
 {
 }
 
-TextBoxIterator::TextBoxIterator(SimpleLineLayout::RunResolver::Iterator simpleLineIterator)
-    : m_pathVariant(simpleLineIterator)
+TextBoxIterator::TextBoxIterator(SimpleLineLayout::RunResolver::Iterator iterator, SimpleLineLayout::RunResolver::Iterator end)
+    : m_pathVariant(TextBoxIterator::SimplePath { iterator, end })
 {
 }
 
 TextBoxIterator& TextBoxIterator::traverseNext()
 {
-    auto simple = [](SimpleLineLayout::RunResolver::Iterator& simpleLineIterator) {
-        ++simpleLineIterator;
+    auto simple = [](TextBoxIterator::SimplePath& path) {
+        ++path.iterator;
     };
 
     auto complex = [](const InlineTextBox*& inlineTextBox) {
@@ -141,8 +185,8 @@ bool TextBoxIterator::operator==(const TextBoxIterator& other) const
     if (m_pathVariant.index() != other.m_pathVariant.index())
         return false;
 
-    auto simple = [&](const SimpleLineLayout::RunResolver::Iterator simpleLineIterator) {
-        return simpleLineIterator == WTF::get<SimpleLineLayout::RunResolver::Iterator>(other.m_pathVariant);
+    auto simple = [&](const TextBoxIterator::SimplePath& path) {
+        return path.iterator == WTF::get<TextBoxIterator::SimplePath>(other.m_pathVariant).iterator;
     };
 
     auto complex = [&](const InlineTextBox* inlineTextBox) {
@@ -152,32 +196,48 @@ bool TextBoxIterator::operator==(const TextBoxIterator& other) const
     return WTF::switchOn(m_pathVariant, simple, complex);
 }
 
-static Optional<SimpleLineLayout::RunResolver> simpleLineRunResolverForText(const RenderText& text)
+bool TextBoxIterator::atEnd() const
 {
-    if (!text.simpleLineLayout())
-        return WTF::nullopt;
-    return SimpleLineLayout::runResolver(downcast<const RenderBlockFlow>(*text.parent()), *text.simpleLineLayout());
+    auto simple = [&](const TextBoxIterator::SimplePath& path) {
+        return path.iterator == path.end;
+    };
+
+    auto complex = [&](const InlineTextBox* inlineTextBox) {
+        return !inlineTextBox;
+    };
+
+    return WTF::switchOn(m_pathVariant, simple, complex);
 }
 
-static auto rangeForText(const RenderText& text, Optional<SimpleLineLayout::RunResolver>& simpleLineRunResolver)
+Provider::Provider() = default;
+Provider::~Provider() = default;
+
+TextBoxIterator Provider::firstTextBoxFor(const RenderText& text)
 {
-    if (simpleLineRunResolver) {
-        auto range = simpleLineRunResolver->rangeForRenderer(text);
-        return WTF::makeIteratorRange(TextBoxIterator(range.begin()), TextBoxIterator(range.end()));
+    if (auto* simpleLineLayout = text.simpleLineLayout()) {
+        auto& parent = downcast<const RenderBlockFlow>(*text.parent());
+        auto& resolver = m_simpleLineLayoutResolvers.ensure(&parent, [&] {
+            return makeUnique<SimpleLineLayout::RunResolver>(parent, *simpleLineLayout);
+        }).iterator->value;
+
+        auto range = resolver->rangeForRenderer(text);
+        return { range.begin(), range.end() };
     }
-    return WTF::makeIteratorRange(TextBoxIterator(text.firstTextBox()), TextBoxIterator(nullptr));
+
+    return TextBoxIterator { text.firstTextBox() };
 }
 
-TextBoxRange::TextBoxRange(const RenderText& text)
-    : m_simpleLineRunResolver(simpleLineRunResolverForText(text))
-    , m_range(rangeForText(text, m_simpleLineRunResolver))
+TextBoxRange Provider::textBoxRangeFor(const RenderText& text)
 {
+    return { firstTextBoxFor(text) };
 }
 
-TextBoxRange textBoxes(const RenderText& text)
+TextBoxIterator Provider::iteratorForInlineTextBox(const InlineTextBox* inlineTextBox)
 {
-    return { text };
+    return TextBoxIterator { inlineTextBox };
 }
 
+
+
 }
 }
index 464c22a..1ef2c89 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "FloatRect.h"
 #include "SimpleLineLayoutResolver.h"
+#include <wtf/HashMap.h>
 #include <wtf/IteratorRange.h>
 #include <wtf/Variant.h>
 #include <wtf/text/StringView.h>
@@ -34,6 +35,7 @@
 namespace WebCore {
 
 class InlineTextBox;
+class Provider;
 class RenderText;
 
 namespace LineLayoutInterface {
@@ -41,12 +43,10 @@ namespace LineLayoutInterface {
 class TextBoxContext;
 class TextBoxIterator;
 
+struct EndIterator { };
+
 class TextBox {
 public:
-    TextBox(const TextBoxIterator& iterator)
-        : m_iterator(iterator)
-    { }
-
     FloatRect rect() const;
     FloatRect logicalRect() const;
 
@@ -56,45 +56,83 @@ public:
 
     StringView text() const;
 
+    // These offsets are relative to the text renderer (not flow).
+    unsigned localStartOffset() const;
+    unsigned localEndOffset() const;
+    unsigned length() const;
+
+protected:
+    TextBox() = default;
+    TextBox(const TextBox&) = default;
+    TextBox(TextBox&&) = default;
+    TextBox& operator=(const TextBox&) = default;
+    TextBox& operator=(TextBox&&) = default;
+
 private:
-    const TextBoxIterator& m_iterator;
+    const TextBoxIterator& iterator() const;
 };
 
-class TextBoxIterator {
+class TextBoxIterator : private TextBox {
 public:
-    TextBoxIterator(const InlineTextBox*);
-    TextBoxIterator(SimpleLineLayout::RunResolver::Iterator);
+    TextBoxIterator() : m_pathVariant(nullptr) { };
+    explicit TextBoxIterator(const InlineTextBox*);
+    TextBoxIterator(SimpleLineLayout::RunResolver::Iterator, SimpleLineLayout::RunResolver::Iterator end);
 
     TextBoxIterator& operator++() { return traverseNext(); }
 
+    explicit operator bool() const { return !atEnd(); }
+
     bool operator==(const TextBoxIterator&) const;
     bool operator!=(const TextBoxIterator& other) const { return !(*this == other); }
 
-    TextBox operator*() const { return { *this }; }
+    bool operator==(EndIterator) const { return atEnd(); }
+    bool operator!=(EndIterator) const { return !atEnd(); }
+
+    const TextBox& operator*() const { return *this; }
+    const TextBox* operator->() const { return this; }
+
+    bool atEnd() const;
 
 private:
     friend class TextBox;
 
     TextBoxIterator& traverseNext();
 
-    Variant<SimpleLineLayout::RunResolver::Iterator, const InlineTextBox*> m_pathVariant;
+    struct SimplePath {
+        SimpleLineLayout::RunResolver::Iterator iterator;
+        SimpleLineLayout::RunResolver::Iterator end;
+    };
+    Variant<SimplePath, const InlineTextBox*> m_pathVariant;
 };
 
 class TextBoxRange {
 public:
-    TextBoxRange(const RenderText&);
+    TextBoxRange(TextBoxIterator begin)
+        : m_begin(begin)
+    {
+    }
 
-    TextBoxIterator begin() const { return m_range.begin(); }
-    TextBoxIterator end() const { return m_range.end(); }
+    TextBoxIterator begin() const { return m_begin; }
+    EndIterator end() const { return { }; }
 
 private:
-    friend class TextBoxIterator;
-
-    Optional<SimpleLineLayout::RunResolver> m_simpleLineRunResolver;
-    WTF::IteratorRange<TextBoxIterator> m_range;
+    TextBoxIterator m_begin;
 };
 
-TextBoxRange textBoxes(const RenderText&);
+class Provider {
+public:
+    Provider();
+    ~Provider();
+
+    TextBoxIterator firstTextBoxFor(const RenderText&);
+    TextBoxRange textBoxRangeFor(const RenderText&);
+
+    // FIXME: Remove.
+    TextBoxIterator iteratorForInlineTextBox(const InlineTextBox*);
+
+private:
+    HashMap<const RenderBlockFlow*, std::unique_ptr<SimpleLineLayout::RunResolver>> m_simpleLineLayoutResolvers;
+};
 
 }
 }