Disallow ruby base from having leading or trailing expansions
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Apr 2015 20:29:23 +0000 (20:29 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Apr 2015 20:29:23 +0000 (20:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142608

Reviewed by David Hyatt.

Source/WebCore:

If we determine that a ruby base should have either a leading or trailing expansion,
we shunt that expansion over to the neighboring RenderText, assuming one exists. This
requires that we teach RenderText how to force leading or trailing expansions if one
wouldn't naturally be present.

Tests: fast/ruby/ruby-expansion-cjk-2.html
       fast/ruby/ruby-expansion-cjk-3.html
       fast/ruby/ruby-expansion-cjk-4.html
       fast/ruby/ruby-expansion-cjk-5.html
       fast/ruby/ruby-expansion-cjk.html

* rendering/InlineFlowBox.cpp:
(WebCore::InlineFlowBox::removeChild): Delete contentIsKnownToFollow.
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::expansionBehavior): Support forced leading and trailing
expansions.
* rendering/InlineTextBox.h:
(WebCore::InlineTextBox::expansionBehavior): Moved to .cpp
* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlockFlow::updateRubyForJustifiedText): Perform relayout even if
there are no expansions left. This is so that ruby bases with no expansions will get
centered.
(WebCore::expansionBehaviorForInlineTextBox): Update to inspect neighboring rubies.
(WebCore::RenderBlockFlow::computeInlineDirectionPositionsForSegment): Use updated
expansionBehaviorForInlineTextBox(). Also center ruby bases if they have no expansion
opportunities.
(WebCore::RenderBlockFlow::createLineBoxesFromBidiRuns): Use nullptr.
(WebCore::RenderBlockFlow::layoutRunsAndFloatsInRange): Ditto.
* rendering/RenderText.cpp:
(WebCore::RenderText::RenderText): Delete contentIsKnownToFollow.
* rendering/RenderText.h:
(WebCore::RenderText::contentIsKnownToFollow): Deleted.
(WebCore::RenderText::setContentIsKnownToFollow): Deleted.

LayoutTests:

Test combinations of CJK, Latin, ruby-in-ruby, simple text codepath, complex
text codepath, RTL, and LTR codepaths.

* fast/ruby/positioned-ruby-text-expected.txt:
* fast/ruby/positioned-ruby-text.html:
* fast/ruby/resources/green.png: Added.
* fast/ruby/resources/ruby-expansion.svg: Added.
* fast/ruby/ruby-expansion-cjk-2-expected.html: Added.
* fast/ruby/ruby-expansion-cjk-2.html: Added.
* fast/ruby/ruby-expansion-cjk-3-expected.html: Added.
* fast/ruby/ruby-expansion-cjk-3.html: Added.
* fast/ruby/ruby-expansion-cjk-4-expected.html: Added.
* fast/ruby/ruby-expansion-cjk-4.html: Added.
* fast/ruby/ruby-expansion-cjk-5-expected.html: Added.
* fast/ruby/ruby-expansion-cjk-5.html: Added.
* fast/ruby/ruby-expansion-cjk-expected.html: Added.
* fast/ruby/ruby-expansion-cjk.html: Added.
* fast/ruby/ruby-justification-expected.html:
* fast/ruby/ruby-justification.html:

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

24 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/ruby/positioned-ruby-text-expected.txt
LayoutTests/fast/ruby/positioned-ruby-text.html
LayoutTests/fast/ruby/resources/green.png [new file with mode: 0644]
LayoutTests/fast/ruby/resources/ruby-expansion.svg [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-2-expected.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-2.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-3-expected.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-3.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-4-expected.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-4.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-5-expected.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-5.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk-expected.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-expansion-cjk.html [new file with mode: 0644]
LayoutTests/fast/ruby/ruby-justification-expected.html
LayoutTests/fast/ruby/ruby-justification.html
Source/WebCore/ChangeLog
Source/WebCore/rendering/InlineFlowBox.cpp
Source/WebCore/rendering/InlineTextBox.cpp
Source/WebCore/rendering/InlineTextBox.h
Source/WebCore/rendering/RenderBlockLineLayout.cpp
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/RenderText.h

index 4bd3f9c..0e3ed6f 100644 (file)
@@ -1,3 +1,30 @@
+2015-04-02  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Disallow ruby base from having leading or trailing expansions
+        https://bugs.webkit.org/show_bug.cgi?id=142608
+
+        Reviewed by David Hyatt.
+
+        Test combinations of CJK, Latin, ruby-in-ruby, simple text codepath, complex
+        text codepath, RTL, and LTR codepaths.
+
+        * fast/ruby/positioned-ruby-text-expected.txt:
+        * fast/ruby/positioned-ruby-text.html:
+        * fast/ruby/resources/green.png: Added.
+        * fast/ruby/resources/ruby-expansion.svg: Added.
+        * fast/ruby/ruby-expansion-cjk-2-expected.html: Added.
+        * fast/ruby/ruby-expansion-cjk-2.html: Added.
+        * fast/ruby/ruby-expansion-cjk-3-expected.html: Added.
+        * fast/ruby/ruby-expansion-cjk-3.html: Added.
+        * fast/ruby/ruby-expansion-cjk-4-expected.html: Added.
+        * fast/ruby/ruby-expansion-cjk-4.html: Added.
+        * fast/ruby/ruby-expansion-cjk-5-expected.html: Added.
+        * fast/ruby/ruby-expansion-cjk-5.html: Added.
+        * fast/ruby/ruby-expansion-cjk-expected.html: Added.
+        * fast/ruby/ruby-expansion-cjk.html: Added.
+        * fast/ruby/ruby-justification-expected.html:
+        * fast/ruby/ruby-justification.html:
+
 2015-04-02  Alexey Proskuryakov  <ap@apple.com>
 
         Clean up access checks in JSHistoryCustom.cpp
index 850a0df..5dbcbce 100644 (file)
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x51
-  RenderBlock {HTML} at (0,0) size 800x51 [color=#FFFFFF]
+  RenderBlock {HTML} at (0,0) size 800x51
     RenderBody {BODY} at (8,8) size 784x35
       RenderRuby (inline) {RUBY} at (0,0) size 784x10
         RenderRubyRun (anonymous) at (0,5) size 784x30
@@ -12,5 +12,5 @@ layer at (0,0) size 800x51
             RenderText {#text} at (0,0) size 784x30
               text run at (0,0) width 784: "Attempt to create a positioned ruby text element. Non-static position is not"
               text run at (0,10) width 784: "supported for ruby text, which should be apparent from the resulting render"
-              text run at (0,20) width 50: "tree."
+              text run at (367,20) width 50: "tree."
       RenderText {#text} at (0,0) size 0x0
index 3ea950e..93aa34f 100644 (file)
@@ -1,4 +1,4 @@
 <!DOCTYPE html>\r
-<html style="font-family: ahem; font-size: 10px; -webkit-font-smoothing: none; color: white;">\r
+<html style="font-family: ahem; font-size: 10px; -webkit-font-smoothing: none;">\r
 <ruby>Attempt to create a positioned ruby text element. Non-static position is not supported for ruby text, which should be apparent from the resulting render tree.<rt style="position: fixed">rubytext</rt></ruby>\r
 </html>\r
diff --git a/LayoutTests/fast/ruby/resources/green.png b/LayoutTests/fast/ruby/resources/green.png
new file mode 100644 (file)
index 0000000..28a1faa
Binary files /dev/null and b/LayoutTests/fast/ruby/resources/green.png differ
diff --git a/LayoutTests/fast/ruby/resources/ruby-expansion.svg b/LayoutTests/fast/ruby/resources/ruby-expansion.svg
new file mode 100644 (file)
index 0000000..a0402f6
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<defs>
+<font id="Litherum" horiz-adv-x="1024">
+<font-face font-family="Litherum" units-per-em="1024" ascent="1024" descent="0"/>
+<glyph unicode="a" horiz-adv-x="1024" d="M0 0v1024h1024v-1024z"/>
+<glyph unicode="&#x304e;" horiz-adv-x="1024" d="M0 0v1024h1024v-1024z"/>
+<glyph unicode="&#x5e2;" horiz-adv-x="1024" d="M0 0v1024h1024v-1024z"/>
+<glyph unicode="&#x62a;" horiz-adv-x="1024" d="M0 0v1024h1024v-1024z"/>
+</font>
+</defs>
+</svg>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-2-expected.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-2-expected.html
new file mode 100644 (file)
index 0000000..c3ae8e0
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>
+<div style="position: absolute; left: 0px; top: 0px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 200px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 380px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 120px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 180px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 360px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 80px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 240px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 220px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 81px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 400px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 360px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 200px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 81px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 380px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 80px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 480px; width: 100%;">
+<div style="position: absolute; width: 300px; height: 20px; left: 0px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 300px; height: 20px; right: 00px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 130px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 380px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 129px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-2.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-2.html
new file mode 100644 (file)
index 0000000..e545724
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("resources/ruby-expansion.svg#Litherum") format(svg);
+}
+</style>
+</head>
+<body style="text-align: justify; font: 40px Litherum; margin: 0px; -webkit-font-smoothing: none;">
+<div dir="rtl">&#x5e2;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div dir="rtl">&#x5e2;&#x5e2;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div dir="rtl">&#x5e2;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x5e2;&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div dir="rtl">&#x5e2;&#x5e2;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x5e2;&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div><ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaa</rt></ruby>a<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaa</rt></ruby> aaaaaaaaaaaaaaaaaaaa</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-3-expected.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-3-expected.html
new file mode 100644 (file)
index 0000000..c732b2c
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>
+<div style="position: absolute; left: 0px; top: 0px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 199px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 40px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 166px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 166px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 40px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 120px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 265px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 40px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 210px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 80px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 40px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 240px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 135px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 40px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 80px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 550px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 40px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 360px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 199px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; left: 0px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 40px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 166px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 166px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 40px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 480px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 135px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; left: 0px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 40px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 80px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 550px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 40px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-3.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-3.html
new file mode 100644 (file)
index 0000000..594a22f
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("resources/ruby-expansion.svg#Litherum") format(svg);
+}
+</style>
+</head>
+<body style="text-align: justify; font: 40px Litherum; margin: 0px; -webkit-font-smoothing: none;">
+<div dir="rtl"><span style="color: green;">&#x5e2;</span>&#x5e2;<ruby><rb><span style="color: green;">&#x304e;</span>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><span style="color: green;">&#x5e2;</span>&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div dir="rtl"><span style="color: green;">&#x5e2;</span>&#x5e2;<ruby><rb><span style="color: green;">&#x5e2;</span>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><span style="color: green;">&#x5e2;</span>&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div dir="rtl"><span style="color: green;">&#x5e2;</span>&#x5e2;<ruby><rb><span style="color: green;">&#x304e;</span>&#x5e2;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><span style="color: green;">&#x5e2;</span>&#x5e2; aaaaaaaaaaaaaaaaaaaa</div>
+<div><span style="color: green;">a</span>a<ruby><rb><span style="color: green;">&#x304e;</span>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><span style="color: green;">a</span>a aaaaaaaaaaaaaaaaaaaa</div>
+<div><span style="color: green;">a</span>a<ruby><rb><span style="color: green;">a</span>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><span style="color: green;">a</span>a aaaaaaaaaaaaaaaaaaaa</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-4-expected.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-4-expected.html
new file mode 100644 (file)
index 0000000..dcf1c02
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("resources/ruby-expansion.svg#Litherum") format(svg);
+}
+</style>
+</head>
+<body style="text-align: justify; font-size: 40px; margin: 0px; -webkit-font-smoothing: none;">
+<div>e&#x300;a&#x300;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>e&#x300;a&#x300; <span style="font-family: Litherum;">aaaaaaaaaaaaaaaaaaaa</span></div>
+<div style="font-family: Litherum;">
+<div style="position: absolute; left: 0px; top: 126px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 199px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 40px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 166px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 166px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 40px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: green;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 239px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 200px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 400px; height: 20px; left: 199px; top: 21px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 40px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 120px; top: 40px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 193px; top: 40px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 193px; top: 40px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 119px; top: 40px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 40px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 91px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 380px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 100px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 100px; height: 50px; left: 0px; top: 10px; background: rgb(0, 255, 0);"></div>
+<div style="position: absolute; width: 41px; height: 41px; right: 479px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-4.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-4.html
new file mode 100644 (file)
index 0000000..50f3afb
--- /dev/null
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("resources/ruby-expansion.svg#Litherum") format(svg);
+}
+</style>
+</head>
+<body style="text-align: justify; font-size: 40px; margin: 0px; -webkit-font-smoothing: none;">
+<div>&#xe8;&#xe0;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#xe8;&#xe0; <span style="font-family: Litherum;">aaaaaaaaaaaaaaaaaaaa</span></div>
+<div style="font-family: Litherum;">
+<div dir="rtl"><span style="color: green;">&#x62a;</span>&#x62a;<ruby><rb><span style="color: green;">&#x304e;</span>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><span style="color: green;">&#x62a;</span>&#x62a; aaaaaaaaaaaaaaaaaaaa</div>
+<div>a<ruby><rb>&#x304e;<ruby><rb>&#x304e;&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>a <span style="font-family: Litherum;">aaaaaaaaaaaaaaaaaaaa</span></div>
+<div><img src="resources/green.png"><ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>a <span style="font-family: Litherum;">aaaaaaaaaaaaaaaaaaaa</span></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-5-expected.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-5-expected.html
new file mode 100644 (file)
index 0000000..8ee56e3
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+</head>
+<body style="text-align: justify; font: 40px Litherum; margin: 0px; -webkit-font-smoothing: none;">
+<div style="position: absolute; left: 0px; top: 0px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; right: 100px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 480px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 100px; height: 50px; right: 0px; top: 10px; background: rgb(0, 255, 0);"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-5.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-5.html
new file mode 100644 (file)
index 0000000..e03a4d8
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("resources/ruby-expansion.svg#Litherum") format(svg);
+}
+</style>
+</head>
+<body style="text-align: justify; font: 40px Litherum; margin: 0px; -webkit-font-smoothing: none;">
+<div>a<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby><img src="resources/green.png"> <span style="font-family: Litherum;">aaaaaaaaaaaaaaaaaaaa</span></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk-expected.html b/LayoutTests/fast/ruby/ruby-expansion-cjk-expected.html
new file mode 100644 (file)
index 0000000..488d619
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<head>
+</head>
+<body>
+<div style="position: absolute; left: 0px; top: 0px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 200px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 380px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 120px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 199px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 153px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 606px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 240px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 199px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 153px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 606px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 360px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 200px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 81px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 41px; height: 41px; left: 380px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 80px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+<div style="position: absolute; left: 0px; top: 480px; width: 100%;">
+<div style="position: absolute; width: 400px; height: 20px; left: 70px; top: 0px; background: black;"></div>
+<div style="position: absolute; width: 81px; height: 41px; left: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 81px; height: 41px; left: 230px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 81px; height: 41px; left: 460px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 40px; height: 41px; right: 0px; top: 19px; background: black;"></div>
+<div style="position: absolute; width: 800px; height: 41px; left: 0px; top: 70px; background: black;"></div>
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/ruby/ruby-expansion-cjk.html b/LayoutTests/fast/ruby/ruby-expansion-cjk.html
new file mode 100644 (file)
index 0000000..bda3c86
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8"/>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("resources/ruby-expansion.svg#Litherum") format(svg);
+}
+</style>
+</head>
+<body style="text-align: justify; font: 40px Litherum; margin: 0px; -webkit-font-smoothing: none;">
+<div>&#x304e;<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x304e;aaaaaaaaaaaaaaaaaaaa</div>
+<div>&#x304e;<ruby><rb>a&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x304e;aaaaaaaaaaaaaaaaaaaa</div>
+<div>&#x304e;<ruby><rb>&#x304e;a</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>&#x304e;aaaaaaaaaaaaaaaaaaaa</div>
+<div>aa<ruby><rb>&#x304e;</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>aa aaaaaaaaaaaaaaaaaaaa</div>
+<div>aa<ruby><rb>aa</rb><rt>aaaaaaaaaaaaaaaaaaaa</rt></ruby>aa a aaaaaaaaaaaaaaaaaaaa</div>
+</body>
+</html>
index 6a41c91..7273f7b 100644 (file)
@@ -13,7 +13,7 @@ abcdefg <ruby>abcdefg<rt><span style="color: transparent;">a</span></ruby> abcde
 abcdefg <ruby>a<rt><span style="color: transparent;">a</span></ruby> abcdefg mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
 </div>
 <div>
-a<span style="background: green;">&#x685c;</span>b mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+a<span">&#x685c;</span>b mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
 </div>
 </div>
 <div style="font-family: Ahem; font-size: 16px;">
index fb8ee91..fe79554 100644 (file)
@@ -13,7 +13,7 @@ This test makes sure that ruby inside text-align: justify has its contents justi
 abcdefg <ruby>a<rt><span style="color: transparent;">aaaaaaaaaaaaaaaaaaaaaaa</span></ruby> abcdefg mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
 </div>
 <div>
-a<ruby><rb style="background: green;">&#x685c;</rb><rt> </ruby>b mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+a<ruby><rb>&#x685c;</rb><rt> </ruby>b mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
 </div>
 <div style="font-family: Ahem;">
 <ruby>abcdefg abcdefg<rt>a</ruby> mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
index f97a11e..b6d05a4 100644 (file)
@@ -1,3 +1,44 @@
+2015-04-02  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Disallow ruby base from having leading or trailing expansions
+        https://bugs.webkit.org/show_bug.cgi?id=142608
+
+        Reviewed by David Hyatt.
+
+        If we determine that a ruby base should have either a leading or trailing expansion,
+        we shunt that expansion over to the neighboring RenderText, assuming one exists. This
+        requires that we teach RenderText how to force leading or trailing expansions if one
+        wouldn't naturally be present.
+
+        Tests: fast/ruby/ruby-expansion-cjk-2.html
+               fast/ruby/ruby-expansion-cjk-3.html
+               fast/ruby/ruby-expansion-cjk-4.html
+               fast/ruby/ruby-expansion-cjk-5.html
+               fast/ruby/ruby-expansion-cjk.html
+
+        * rendering/InlineFlowBox.cpp:
+        (WebCore::InlineFlowBox::removeChild): Delete contentIsKnownToFollow.
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::expansionBehavior): Support forced leading and trailing
+        expansions.
+        * rendering/InlineTextBox.h:
+        (WebCore::InlineTextBox::expansionBehavior): Moved to .cpp
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlockFlow::updateRubyForJustifiedText): Perform relayout even if
+        there are no expansions left. This is so that ruby bases with no expansions will get
+        centered.
+        (WebCore::expansionBehaviorForInlineTextBox): Update to inspect neighboring rubies.
+        (WebCore::RenderBlockFlow::computeInlineDirectionPositionsForSegment): Use updated
+        expansionBehaviorForInlineTextBox(). Also center ruby bases if they have no expansion
+        opportunities.
+        (WebCore::RenderBlockFlow::createLineBoxesFromBidiRuns): Use nullptr.
+        (WebCore::RenderBlockFlow::layoutRunsAndFloatsInRange): Ditto.
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::RenderText): Delete contentIsKnownToFollow.
+        * rendering/RenderText.h:
+        (WebCore::RenderText::contentIsKnownToFollow): Deleted.
+        (WebCore::RenderText::setContentIsKnownToFollow): Deleted.
+
 2015-04-02  Alexey Proskuryakov  <ap@apple.com>
 
         Clean up access checks in JSHistoryCustom.cpp
index 0234958..1adbd2a 100644 (file)
@@ -179,14 +179,6 @@ void InlineFlowBox::removeChild(InlineBox* child)
     if (!isDirty())
         dirtyLineBoxes();
 
-    if (child->prevLeafChild() && is<InlineTextBox>(child->prevLeafChild())) {
-        if (is<InlineTextBox>(child))
-            downcast<InlineTextBox>(child->prevLeafChild())->renderer().setContentIsKnownToFollow(downcast<InlineTextBox>(child)->renderer().contentIsKnownToFollow());
-        // FIXME: Handle the case where we remove the last inline box, and it's not a text box. If we're trying to share
-        // expansion opportunites both inside and outside a replaced element (such as for ruby bases), we need to search
-        // outside the current inline box tree to determine if there is content that follows the new last inline item.
-    }
-
     root().childRemoved(child);
 
     if (child == m_firstChild)
index 08df568..d910318 100644 (file)
@@ -1394,6 +1394,27 @@ TextRun InlineTextBox::constructTextRun(const RenderStyle& style, const FontCasc
     return run;
 }
 
+ExpansionBehavior InlineTextBox::expansionBehavior() const
+{
+    ExpansionBehavior leadingBehavior;
+    if (forceLeadingExpansion())
+        leadingBehavior = ForceLeadingExpansion;
+    else if (canHaveLeadingExpansion())
+        leadingBehavior = AllowLeadingExpansion;
+    else
+        leadingBehavior = ForbidLeadingExpansion;
+
+    ExpansionBehavior trailingBehavior;
+    if (forceTrailingExpansion())
+        trailingBehavior = ForceTrailingExpansion;
+    else if (expansion() && nextLeafChild() && !nextLeafChild()->isLineBreak())
+        trailingBehavior = AllowTrailingExpansion;
+    else
+        trailingBehavior = ForbidTrailingExpansion;
+
+    return leadingBehavior | trailingBehavior;
+}
+
 #if ENABLE(TREE_DEBUGGING)
 
 const char* InlineTextBox::boxName() const
index 33d7b74..1f7b0e0 100644 (file)
@@ -166,11 +166,7 @@ private:
 
     void computeRectForReplacementMarker(RenderedDocumentMarker&, const RenderStyle&, const FontCascade&);
 
-    ExpansionBehavior expansionBehavior() const
-    {
-        return (canHaveLeadingExpansion() ? AllowLeadingExpansion : ForbidLeadingExpansion)
-            | (renderer().contentIsKnownToFollow() || (expansion() && nextLeafChild() && !nextLeafChild()->isLineBreak()) ? AllowTrailingExpansion : ForbidTrailingExpansion);
-    }
+    ExpansionBehavior expansionBehavior() const;
 
     void behavesLikeText() const = delete;
 
index ab9d2bd..b808917 100644 (file)
@@ -570,33 +570,29 @@ void RenderBlockFlow::updateRubyForJustifiedText(RenderRubyRun& rubyRun, BidiRun
         totalOpportunitiesInRun += opportunitiesInRun;
     }
 
-    if (totalOpportunitiesInRun) {
-        ASSERT(!rubyRun.hasOverrideWidth());
-        float newBaseWidth = rubyRun.logicalWidth() + totalExpansion + marginStartForChild(rubyRun) + marginEndForChild(rubyRun);
-        float newRubyRunWidth = rubyRun.logicalWidth() + totalExpansion;
-        rubyBase.setInitialOffset((newRubyRunWidth - newBaseWidth) / 2);
-        rubyRun.setOverrideLogicalContentWidth(newRubyRunWidth);
-        rubyRun.setNeedsLayout(MarkOnlyThis);
-        rootBox.markDirty();
-        if (RenderRubyText* rubyText = rubyRun.rubyText()) {
-            if (RootInlineBox* textRootBox = rubyText->firstRootBox())
-                textRootBox->markDirty();
-        }
-        rubyRun.layoutBlock(true);
-        rubyRun.clearOverrideLogicalContentWidth();
-        r.box()->setExpansion(newRubyRunWidth - r.box()->logicalWidth());
-
-        // This relayout caused the size of the RenderRubyText and the RenderRubyBase to change, dependent on the line's current expansion. Next time we relayout the
-        // RenderRubyRun, make sure that we relayout the RenderRubyBase and RenderRubyText as well.
-        rubyBase.setNeedsLayout(MarkOnlyThis);
-        if (RenderRubyText* rubyText = rubyRun.rubyText())
-            rubyText->setNeedsLayout(MarkOnlyThis);
-        if (rubyBase.lastLeafChild() && is<RenderText>(rubyBase.lastLeafChild()) && r.box() && r.box()->nextLeafChild() && !r.box()->nextLeafChild()->isLineBreak())
-            downcast<RenderText>(rubyBase.lastLeafChild())->setContentIsKnownToFollow(true);
-
-        totalLogicalWidth += totalExpansion;
-        expansionOpportunityCount -= totalOpportunitiesInRun;
+    ASSERT(!rubyRun.hasOverrideWidth());
+    float newBaseWidth = rubyRun.logicalWidth() + totalExpansion + marginStartForChild(rubyRun) + marginEndForChild(rubyRun);
+    float newRubyRunWidth = rubyRun.logicalWidth() + totalExpansion;
+    rubyBase.setInitialOffset((newRubyRunWidth - newBaseWidth) / 2);
+    rubyRun.setOverrideLogicalContentWidth(newRubyRunWidth);
+    rubyRun.setNeedsLayout(MarkOnlyThis);
+    rootBox.markDirty();
+    if (RenderRubyText* rubyText = rubyRun.rubyText()) {
+        if (RootInlineBox* textRootBox = rubyText->firstRootBox())
+            textRootBox->markDirty();
     }
+    rubyRun.layoutBlock(true);
+    rubyRun.clearOverrideLogicalContentWidth();
+    r.box()->setExpansion(newRubyRunWidth - r.box()->logicalWidth());
+
+    // This relayout caused the size of the RenderRubyText and the RenderRubyBase to change, dependent on the line's current expansion. Next time we relayout the
+    // RenderRubyRun, make sure that we relayout the RenderRubyBase and RenderRubyText as well.
+    rubyBase.setNeedsLayout(MarkOnlyThis);
+    if (RenderRubyText* rubyText = rubyRun.rubyText())
+        rubyText->setNeedsLayout(MarkOnlyThis);
+
+    totalLogicalWidth += totalExpansion;
+    expansionOpportunityCount -= totalOpportunitiesInRun;
 }
 
 void RenderBlockFlow::computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, const Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float totalLogicalWidth, float availableLogicalWidth)
@@ -723,10 +719,59 @@ void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* line
     lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing);
 }
 
-static inline ExpansionBehavior expansionBehaviorForInlineTextBox(bool isAfterExpansion)
+static inline ExpansionBehavior expansionBehaviorForInlineTextBox(RenderBlockFlow& block, InlineTextBox& textBox, BidiRun* previousRun, BidiRun* nextRun, ETextAlign textAlign, bool isAfterExpansion)
 {
-    ExpansionBehavior result = AllowTrailingExpansion;
-    result |= isAfterExpansion ? ForbidLeadingExpansion : AllowLeadingExpansion;
+    ExpansionBehavior result = 0;
+    bool setLeadingExpansion = false;
+    bool setTrailingExpansion = false;
+    if (textAlign == JUSTIFY) {
+        // If the next box is ruby, and we're justifying, and the first box in the ruby base has a leading expansion, and we are a text box, then
+        // force a trailing expansion.
+        if (nextRun && is<RenderRubyRun>(nextRun->renderer()) && downcast<RenderRubyRun>(nextRun->renderer()).rubyBase() && nextRun->renderer().style().collapseWhiteSpace()) {
+            auto& rubyBase = *downcast<RenderRubyRun>(nextRun->renderer()).rubyBase();
+            if (rubyBase.firstRootBox() && !rubyBase.firstRootBox()->nextRootBox()) {
+                if (auto* leafChild = rubyBase.firstRootBox()->firstLeafChild()) {
+                    if (is<InlineTextBox>(*leafChild)) {
+                        // FIXME: This leadingExpansionOpportunity doesn't actually work because it doesn't perform the UBA
+                        if (FontCascade::leadingExpansionOpportunity(downcast<RenderText>(leafChild->renderer()).stringView(), leafChild->direction())) {
+                            setTrailingExpansion = true;
+                            result |= ForceTrailingExpansion;
+                        }
+                    }
+                }
+            }
+        }
+        // Same thing, except if we're following a ruby
+        if (previousRun && is<RenderRubyRun>(previousRun->renderer()) && downcast<RenderRubyRun>(previousRun->renderer()).rubyBase() && previousRun->renderer().style().collapseWhiteSpace()) {
+            auto& rubyBase = *downcast<RenderRubyRun>(previousRun->renderer()).rubyBase();
+            if (rubyBase.firstRootBox() && !rubyBase.firstRootBox()->nextRootBox()) {
+                if (auto* leafChild = rubyBase.firstRootBox()->lastLeafChild()) {
+                    if (is<InlineTextBox>(*leafChild)) {
+                        // FIXME: This leadingExpansionOpportunity doesn't actually work because it doesn't perform the UBA
+                        if (FontCascade::trailingExpansionOpportunity(downcast<RenderText>(leafChild->renderer()).stringView(), leafChild->direction())) {
+                            setLeadingExpansion = true;
+                            result |= ForceLeadingExpansion;
+                        }
+                    }
+                }
+            }
+        }
+        // If we're the first box inside a ruby base, forbid a leading expansion, and vice-versa
+        if (is<RenderRubyBase>(block)) {
+            RenderRubyBase& rubyBase = downcast<RenderRubyBase>(block);
+            if (&textBox == rubyBase.firstRootBox()->firstLeafChild()) {
+                setLeadingExpansion = true;
+                result |= ForbidLeadingExpansion;
+            } if (&textBox == rubyBase.firstRootBox()->lastLeafChild()) {
+                setTrailingExpansion = true;
+                result |= ForbidTrailingExpansion;
+            }
+        }
+    }
+    if (!setLeadingExpansion)
+        result |= isAfterExpansion ? ForbidLeadingExpansion : AllowLeadingExpansion;
+    if (!setTrailingExpansion)
+        result |= AllowTrailingExpansion;
     return result;
 }
 
@@ -771,9 +816,9 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo
     unsigned expansionOpportunityCount = 0;
     bool isAfterExpansion = is<RenderRubyBase>(*this) ? downcast<RenderRubyBase>(*this).isAfterExpansion() : true;
     Vector<unsigned, 16> expansionOpportunities;
-    RenderObject* previousObject = nullptr;
 
     BidiRun* run = firstRun;
+    BidiRun* previousRun = nullptr;
     for (; run; run = run->next()) {
         if (!run->box() || run->renderer().isOutOfFlowPositioned() || run->box()->isLineBreak()) {
             continue; // Positioned objects are only participating to figure out their
@@ -784,7 +829,7 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo
             auto& renderText = downcast<RenderText>(run->renderer());
             auto& textBox = downcast<InlineTextBox>(*run->box());
             if (textAlign == JUSTIFY && run != trailingSpaceRun) {
-                ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(isAfterExpansion);
+                ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(*this, textBox, previousRun, run->next(), textAlign, isAfterExpansion);
                 applyExpansionBehavior(textBox, expansionBehavior);
                 unsigned opportunitiesInRun;
                 std::tie(opportunitiesInRun, isAfterExpansion) = FontCascade::expansionOpportunityCount(renderText.stringView(run->m_start, run->m_stop), run->box()->direction(), expansionBehavior);
@@ -811,7 +856,7 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo
                         auto& textBox = downcast<InlineTextBox>(*leafChild);
                         encounteredJustifiedRuby = true;
                         auto& renderText = downcast<RenderText>(leafChild->renderer());
-                        ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(isAfterExpansion);
+                        ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(*rubyBase, textBox, nullptr, nullptr, textAlign, isAfterExpansion);
                         applyExpansionBehavior(textBox, expansionBehavior);
                         unsigned opportunitiesInRun;
                         std::tie(opportunitiesInRun, isAfterExpansion) = FontCascade::expansionOpportunityCount(renderText.stringView(), leafChild->direction(), expansionBehavior);
@@ -827,36 +872,24 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo
             if (!is<RenderInline>(run->renderer())) {
                 auto& renderBox = downcast<RenderBox>(run->renderer());
                 if (is<RenderRubyRun>(renderBox))
-                    setMarginsForRubyRun(run, downcast<RenderRubyRun>(renderBox), previousObject, lineInfo);
+                    setMarginsForRubyRun(run, downcast<RenderRubyRun>(renderBox), previousRun ? &previousRun->renderer() : nullptr, lineInfo);
                 run->box()->setLogicalWidth(logicalWidthForChild(renderBox));
                 totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
             }
         }
 
         totalLogicalWidth += run->box()->logicalWidth();
-        previousObject = &run->renderer();
+        previousRun = run;
     }
 
     if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
-        bool shouldShareExpansionsWithContainingLine = true;
-        if (is<RenderRubyBase>(*this)) {
-            if (RenderRubyRun* rubyRun = downcast<RenderRubyBase>(*this).rubyRun()) {
-                if (RenderElement* rubyElement = rubyRun->parent()) {
-                    if (rubyElement->style().display() == INLINE) {
-                        if (RenderBlock* containingBlock = rubyElement->containingBlock()) {
-                            if (containingBlock->style().textAlign() == JUSTIFY)
-                                shouldShareExpansionsWithContainingLine = false;
-                        }
-                    }
-                }
-            }
-        }
-        if (shouldShareExpansionsWithContainingLine) {
-            expansionOpportunities.last()--;
-            expansionOpportunityCount--;
-        }
+        expansionOpportunities.last()--;
+        expansionOpportunityCount--;
     }
 
+    if (is<RenderRubyBase>(*this) && !expansionOpportunityCount)
+        textAlign = CENTER;
+
     updateLogicalWidthForAlignment(textAlign, lineBox, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
 
     computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
@@ -1057,14 +1090,14 @@ static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver,
 RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
 {
     if (!bidiRuns.runCount())
-        return 0;
+        return nullptr;
 
     // FIXME: Why is this only done when we had runs?
     lineInfo.setLastLine(!end.renderer());
 
     RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
     if (!lineBox)
-        return 0;
+        return nullptr;
 
     lineBox->setBidiLevel(bidiLevel);
     lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
@@ -1255,7 +1288,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
             constructBidiRunsForSegment(resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
             ASSERT(resolver.position() == end);
 
-            BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0;
+            BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : nullptr;
 
             if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated()) {
                 bidiRuns.logicallyLastRun()->m_hasHyphen = true;
index bf05674..8afeff6 100644 (file)
@@ -180,7 +180,6 @@ inline RenderText::RenderText(Node& node, const String& text)
     , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
     , m_useBackslashAsYenSymbol(false)
     , m_originalTextDiffersFromRendered(false)
-    , m_contentIsKnownToFollow(false)
 #if ENABLE(IOS_TEXT_AUTOSIZING)
     , m_candidateComputedTextSize(0)
 #endif
index 9d9454a..70bfeed 100644 (file)
@@ -165,9 +165,6 @@ public:
 
     LayoutUnit topOfFirstText() const;
 
-    bool contentIsKnownToFollow() { return m_contentIsKnownToFollow; }
-    void setContentIsKnownToFollow(bool contentIsKnownToFollow) { m_contentIsKnownToFollow = contentIsKnownToFollow; }
-
 protected:
     virtual void computePreferredLogicalWidths(float leadWidth);
     virtual void willBeDestroyed() override;
@@ -218,7 +215,6 @@ private:
     mutable unsigned m_knownToHaveNoOverflowAndNoFallbackFonts : 1;
     unsigned m_useBackslashAsYenSymbol : 1;
     unsigned m_originalTextDiffersFromRendered : 1;
-    unsigned m_contentIsKnownToFollow : 1;
 
 #if ENABLE(IOS_TEXT_AUTOSIZING)
     // FIXME: This should probably be part of the text sizing structures in Document instead. That would save some memory.