<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[198683] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/198683">198683</a></dd>
<dt>Author</dt> <dd>hyatt@apple.com</dd>
<dt>Date</dt> <dd>2016-03-25 12:25:05 -0700 (Fri, 25 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Implement the allow-end value of the hanging-punctuation CSS property.
https://bugs.webkit.org/show_bug.cgi?id=104996

Reviewed by Simon Fraser.

Source/WebCore:

Added new tests in fast/text.

* rendering/RenderBlockLineLayout.cpp:
(WebCore::RenderBlockFlow::constructLine):
Fix a bug where empty RenderInlines were incorrectly excluding their end borders if
they occurred at the end of a line. Needed to adequately test allow-end and empty
inline borders.

* rendering/RenderText.cpp:
(WebCore::RenderText::isHangableStopOrComma):
Helper function that identifies the hangable stops and commas.

* rendering/RenderText.h:
Add new isHangableStopOrComma function to RenderText.

* rendering/line/BreakingContext.h:
(WebCore::BreakingContext::lineBreak):
(WebCore::BreakingContext::lineWidth):
(WebCore::BreakingContext::atEnd):
(WebCore::BreakingContext::fitsOnLineOrHangsAtEnd):
(WebCore::BreakingContext::clearLineBreakIfFitsOnLine):
(WebCore::BreakingContext::commitLineBreakAtCurrentWidth):
(WebCore::BreakingContext::handleBR):
(WebCore::BreakingContext::handleEmptyInline):
(WebCore::BreakingContext::handleReplaced):
(WebCore::tryHyphenating):
(WebCore::BreakingContext::computeAdditionalBetweenWordsWidth):
(WebCore::BreakingContext::handleText):
(WebCore::BreakingContext::commitAndUpdateLineBreakIfNeeded):
Modified breaking rules to handle allow-end. The basic idea is to see if you can
fit without the comma and only hang if you do, and if nothing else gets added to the
line after the comma. This involves tracking a new state, m_hangsAtEnd, that can
be set/cleared while iterating over the objects that will end up on the line.

LayoutTests:

* fast/text/hanging-punctuation-allow-end-basic-expected.html: Added.
* fast/text/hanging-punctuation-allow-end-basic.html: Added.
* fast/text/hanging-punctuation-allow-end-expected.html: Added.
* fast/text/hanging-punctuation-allow-end-inlines-expected.html: Added.
* fast/text/hanging-punctuation-allow-end-inlines.html: Added.
* fast/text/hanging-punctuation-allow-end.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderBlockLineLayoutcpp">trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderTextcpp">trunk/Source/WebCore/rendering/RenderText.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderTexth">trunk/Source/WebCore/rendering/RenderText.h</a></li>
<li><a href="#trunkSourceWebCorerenderinglineBreakingContexth">trunk/Source/WebCore/rendering/line/BreakingContext.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationallowendbasicexpectedhtml">trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationallowendbasichtml">trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationallowendexpectedhtml">trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationallowendinlinesexpectedhtml">trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationallowendinlineshtml">trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationallowendhtml">trunk/LayoutTests/fast/text/hanging-punctuation-allow-end.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (198682 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-03-25 18:44:38 UTC (rev 198682)
+++ trunk/LayoutTests/ChangeLog        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2016-03-23  Dave Hyatt  &lt;hyatt@apple.com&gt;
+
+        Implement the allow-end value of the hanging-punctuation CSS property.
+        https://bugs.webkit.org/show_bug.cgi?id=104996
+
+        Reviewed by Simon Fraser.
+
+        * fast/text/hanging-punctuation-allow-end-basic-expected.html: Added.
+        * fast/text/hanging-punctuation-allow-end-basic.html: Added.
+        * fast/text/hanging-punctuation-allow-end-expected.html: Added.
+        * fast/text/hanging-punctuation-allow-end-inlines-expected.html: Added.
+        * fast/text/hanging-punctuation-allow-end-inlines.html: Added.
+        * fast/text/hanging-punctuation-allow-end.html: Added.
+
</ins><span class="cx"> 2016-03-25  Caitlin Potter  &lt;caitp@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] implement String.prototype.padStart() and String.prototype.padEnd() proposal
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationallowendbasicexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic-expected.html (0 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic-expected.html        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;meta charset=&quot;UTF-8&quot;&gt;
+            &lt;style&gt;
+                .hang { white-space: pre; }
+                    .not-hang { white-space: pre; }
+                    .frame { width: 65px; font-family: ahem; border: solid 3px cyan; }
+            &lt;/style&gt;
+        &lt;/head&gt;
+    &lt;body&gt;
+        &lt;!--
+          Test for checking overflowing conditions of hanging-punctuation: allow-end.
+          http://www.w3.org/TR/2012/WD-css3-text-20121113/#hanging-punctuation0
+          --&gt;
+        &lt;!-- Overflow occurred at U+3001. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;ab c&amp;#x3001;&lt;/div&gt;
+        &lt;!-- Overflow occurred at &quot;d&quot;. This should NOT hang. --&gt;
+        &lt;div class=&quot;not-hang frame&quot;&gt;ab
+cd&amp;#x3001;&lt;/div&gt;
+        &lt;!-- Overflow occurred at first U+3001. This should NOT hang. --&gt;
+        &lt;div class=&quot;not-hang frame&quot;&gt;ab
+c&amp;#x3001;&amp;#x3001;&lt;/div&gt;
+        &lt;!-- Overflow occurred at second U+3001. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;a b&amp;#x3001;&amp;#x3001;&lt;/div&gt;
+        &lt;!-- Hanging with soft hyphen. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;a b&amp;shy;c&amp;#x3001;&lt;/div&gt;
+        &lt;!-- Overflow occurred at U+3001 and there is a &lt;br&gt; after it. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;ab c&amp;#x3001;&lt;br&gt;&lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationallowendbasichtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic.html (0 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-basic.html        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+    &lt;head&gt;
+        &lt;meta charset=&quot;UTF-8&quot;&gt;
+            &lt;style&gt;
+                    .hang { hanging-punctuation: allow-end; }
+                    .not-hang { hanging-punctuation: allow-end; }
+                    .frame { width: 65px; font-family: ahem; border: solid 3px cyan; }
+            &lt;/style&gt;
+        &lt;/head&gt;
+    &lt;body&gt;
+        &lt;!--
+          Test for checking overflowing conditions of hanging-punctuation: allow-end.
+          http://www.w3.org/TR/2012/WD-css3-text-20121113/#hanging-punctuation0
+          --&gt;
+        &lt;!-- Overflow occurred at U+3001. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;
+            ab c&amp;#x3001;
+        &lt;/div&gt;
+        &lt;!-- Overflow occurred at &quot;d&quot;. This should NOT hang. --&gt;
+        &lt;div class=&quot;not-hang frame&quot;&gt;
+            ab cd&amp;#x3001;
+            &lt;/div&gt;
+        &lt;!-- Overflow occurred at first U+3001. This should NOT hang. --&gt;
+        &lt;div class=&quot;not-hang frame&quot;&gt;
+            ab c&amp;#x3001;&amp;#x3001;
+            &lt;/div&gt;
+        &lt;!-- Overflow occurred at second U+3001. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;
+            a b&amp;#x3001;&amp;#x3001;
+            &lt;/div&gt;
+        &lt;!-- Hanging with soft hyphen. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;
+            a b&amp;shy;c&amp;#x3001;
+            &lt;/div&gt;
+        &lt;!-- Overflow occurred at U+3001 and there is a &lt;br&gt; after it. This should hang. --&gt;
+        &lt;div class=&quot;hang frame&quot;&gt;
+            ab c&amp;#x3001;&lt;br&gt;
+        &lt;/div&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationallowendexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-expected.html (0 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-expected.html        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+&lt;head&gt;
+&lt;style&gt;
+    body { font-family: 'Ahem'; color:green }
+    .hang { white-space:pre; margin:1em; width:5em; border:2px solid black }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;float:left&quot; class=&quot;hang&quot;&gt;12 34,&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,
+1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify;&quot;&gt;12 34,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,&lt;br&gt;12345&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12
+34,56
+1234&lt;br&gt;12345&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12
+34,56
+1234&lt;br&gt;12345&lt;/div&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationallowendinlinesexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines-expected.html (0 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines-expected.html        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+&lt;head&gt;
+&lt;style&gt;
+    body { font-family: 'Ahem'; color:green }
+    .hang { white-space:pre; margin:1em; width:5em; border:2px solid black }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;float:left; width:auto&quot; class=&quot;hang&quot;&gt;12 34,&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,&lt;span&gt;&lt;/span&gt;
+1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12
+34,&lt;span style=&quot;border-left:1em solid black&quot;&gt;&lt;/span&gt;
+1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12
+34,&lt;span style=&quot;border-right:1em solid black&quot;&gt;&lt;/span&gt;
+1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;&lt;span style=&quot;border-right:1em solid black&quot;&gt;12
+34,&lt;/span&gt;
+2345&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12
+34&lt;span style=&quot;border-left:1em solid black&quot;&gt;,&lt;/span&gt;
+2345&lt;/div&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationallowendinlineshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines.html (0 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-allow-end-inlines.html        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+&lt;head&gt;
+&lt;style&gt;
+    body { font-family: 'Ahem'; color:green }
+    .hang { hanging-punctuation: allow-end; margin:1em; width:5em; border:2px solid black }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;float:left; width:auto&quot; class=&quot;hang&quot;&gt;12 34,&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,&lt;span&gt;&lt;/span&gt; 1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,&lt;span style=&quot;border-left:1em solid black&quot;&gt;&lt;/span&gt; 1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,&lt;span style=&quot;border-right:1em solid black&quot;&gt;&lt;/span&gt; 1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;&lt;span style=&quot;border-right:1em solid black&quot;&gt;12 34,&lt;/span&gt; 2345&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34&lt;span style=&quot;border-left:1em solid black&quot;&gt;,&lt;/span&gt; 2345&lt;/div&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationallowendhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-allow-end.html (0 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-allow-end.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-allow-end.html        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+&lt;head&gt;
+&lt;style&gt;
+    body { font-family: 'Ahem'; color:green }
+    .hang { hanging-punctuation: allow-end; margin:1em; width:5em; border:2px solid black }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;float:left&quot; class=&quot;hang&quot;&gt;12 34,&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34, 1234,&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify;&quot;&gt;12 34,&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,&lt;br&gt;12345&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 34,56 1234&lt;br&gt;12345&lt;/div&gt;
+&lt;div class=&quot;hang&quot;&gt;12 &lt;span style=&quot;white-space:nowrap&quot;&gt;34,&lt;div style=&quot;display:inline-block&quot;&gt;56&lt;/div&gt;&lt;/span&gt; 1234&lt;br&gt;12345&lt;/div&gt;
+
+
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (198682 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-03-25 18:44:38 UTC (rev 198682)
+++ trunk/Source/WebCore/ChangeLog        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2016-03-23  Dave Hyatt  &lt;hyatt@apple.com&gt;
+
+        Implement the allow-end value of the hanging-punctuation CSS property.
+        https://bugs.webkit.org/show_bug.cgi?id=104996
+
+        Reviewed by Simon Fraser.
+
+        Added new tests in fast/text.
+
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::RenderBlockFlow::constructLine):
+        Fix a bug where empty RenderInlines were incorrectly excluding their end borders if
+        they occurred at the end of a line. Needed to adequately test allow-end and empty
+        inline borders.
+
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::isHangableStopOrComma):
+        Helper function that identifies the hangable stops and commas.
+
+        * rendering/RenderText.h:
+        Add new isHangableStopOrComma function to RenderText.
+
+        * rendering/line/BreakingContext.h:
+        (WebCore::BreakingContext::lineBreak):
+        (WebCore::BreakingContext::lineWidth):
+        (WebCore::BreakingContext::atEnd):
+        (WebCore::BreakingContext::fitsOnLineOrHangsAtEnd):
+        (WebCore::BreakingContext::clearLineBreakIfFitsOnLine):
+        (WebCore::BreakingContext::commitLineBreakAtCurrentWidth):
+        (WebCore::BreakingContext::handleBR):
+        (WebCore::BreakingContext::handleEmptyInline):
+        (WebCore::BreakingContext::handleReplaced):
+        (WebCore::tryHyphenating):
+        (WebCore::BreakingContext::computeAdditionalBetweenWordsWidth):
+        (WebCore::BreakingContext::handleText):
+        (WebCore::BreakingContext::commitAndUpdateLineBreakIfNeeded):
+        Modified breaking rules to handle allow-end. The basic idea is to see if you can
+        fit without the comma and only hang if you do, and if nothing else gets added to the
+        line after the comma. This involves tracking a new state, m_hangsAtEnd, that can
+        be set/cleared while iterating over the objects that will end up on the line.
+
</ins><span class="cx"> 2016-03-25  Alex Christensen  &lt;achristensen@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Revert most of r198673.
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderBlockLineLayoutcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp (198682 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp        2016-03-25 18:44:38 UTC (rev 198682)
+++ trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -337,7 +337,7 @@
</span><span class="cx">     // paint borders/margins/padding.  This knowledge will ultimately be used when
</span><span class="cx">     // we determine the horizontal positions and widths of all the inline boxes on
</span><span class="cx">     // the line.
</span><del>-    bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()-&gt;renderer().isText() ? !reachedEndOfTextRenderer(bidiRuns) : true;
</del><ins>+    bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()-&gt;renderer().isText() ? !reachedEndOfTextRenderer(bidiRuns) : !is&lt;RenderInline&gt;(bidiRuns.logicallyLastRun()-&gt;renderer());
</ins><span class="cx">     lastRootBox()-&gt;determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, &amp;bidiRuns.logicallyLastRun()-&gt;renderer());
</span><span class="cx"> 
</span><span class="cx">     // Now mark the line boxes as being constructed.
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderTextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderText.cpp (198682 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderText.cpp        2016-03-25 18:44:38 UTC (rev 198682)
+++ trunk/Source/WebCore/rendering/RenderText.cpp        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -546,6 +546,13 @@
</span><span class="cx">     return widthFromCache(font, 0, 1, 0, 0, 0, style);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool RenderText::isHangableStopOrComma(UChar c) const
+{
+    return c == 0x002C || c == 0x002E || c == 0x060C || c == 0x06D4 || c == 0x3001
+        || c == 0x3002 || c == 0xFF0C || c == 0xFF0E || c == 0xFE50 || c == 0xFE51
+        || c == 0xFE52 || c == 0xFF61 || c == 0xFF64;
+}
+
</ins><span class="cx"> unsigned RenderText::firstCharacterIndexStrippingSpaces() const
</span><span class="cx"> {
</span><span class="cx">     if (!style().collapseWhiteSpace())
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderTexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderText.h (198682 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderText.h        2016-03-25 18:44:38 UTC (rev 198682)
+++ trunk/Source/WebCore/rendering/RenderText.h        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -106,7 +106,8 @@
</span><span class="cx">     float hangablePunctuationEndWidth(unsigned index) const;
</span><span class="cx">     unsigned firstCharacterIndexStrippingSpaces() const;
</span><span class="cx">     unsigned lastCharacterIndexStrippingSpaces() const;
</span><del>-
</del><ins>+    bool isHangableStopOrComma(UChar) const;
+    
</ins><span class="cx">     WEBCORE_EXPORT virtual IntRect linesBoundingBox() const;
</span><span class="cx">     LayoutRect linesVisualOverflowBoundingBox() const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderinglineBreakingContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/line/BreakingContext.h (198682 => 198683)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/line/BreakingContext.h        2016-03-25 18:44:38 UTC (rev 198682)
+++ trunk/Source/WebCore/rendering/line/BreakingContext.h        2016-03-25 19:25:05 UTC (rev 198683)
</span><span class="lines">@@ -138,6 +138,8 @@
</span><span class="cx">     InlineIterator lineBreak() { return m_lineBreakHistory.current(); }
</span><span class="cx">     LineWidth&amp; lineWidth() { return m_width; }
</span><span class="cx">     bool atEnd() { return m_atEnd; }
</span><ins>+    
+    bool fitsOnLineOrHangsAtEnd() const { return m_width.fitsOnLine() || m_hangsAtEnd; }
</ins><span class="cx"> 
</span><span class="cx">     void initializeForCurrentObject();
</span><span class="cx"> 
</span><span class="lines">@@ -155,17 +157,21 @@
</span><span class="cx"> #if ENABLE(CSS_TRAILING_WORD)
</span><span class="cx">     InlineIterator optimalLineBreakLocationForTrailingWord();
</span><span class="cx"> #endif
</span><ins>+    
+    float computeAdditionalBetweenWordsWidth(RenderText&amp;, TextLayout*, UChar, WordTrailingSpace&amp;, HashSet&lt;const Font*&gt;&amp; fallbackFonts, WordMeasurements&amp;, const FontCascade&amp;, bool isFixedPitch, unsigned lastSpace, float lastSpaceWordSpacing, float wordSpacingForWordMeasurement, unsigned offset);
</ins><span class="cx"> 
</span><span class="cx">     void clearLineBreakIfFitsOnLine(bool ignoringTrailingSpace = false)
</span><span class="cx">     {
</span><del>-        if (m_width.fitsOnLine(ignoringTrailingSpace) || m_lastWS == NOWRAP)
</del><ins>+        if (m_width.fitsOnLine(ignoringTrailingSpace) || m_lastWS == NOWRAP || m_hangsAtEnd)
</ins><span class="cx">             m_lineBreakHistory.clear();
</span><ins>+        m_hangsAtEnd = false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void commitLineBreakAtCurrentWidth(RenderObject&amp; object, unsigned offset = 0, int nextBreak = -1)
</span><span class="cx">     {
</span><span class="cx">         m_width.commit();
</span><span class="cx">         m_lineBreakHistory.moveTo(&amp;object, offset, nextBreak);
</span><ins>+        m_hangsAtEnd = false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="lines">@@ -283,6 +289,8 @@
</span><span class="cx">     bool m_allowImagesToBreak;
</span><span class="cx">     bool m_atEnd;
</span><span class="cx">     bool m_hadUncommittedWidthBeforeCurrent;
</span><ins>+    
+    bool m_hangsAtEnd { false };
</ins><span class="cx"> 
</span><span class="cx">     LineMidpointState&amp; m_lineMidpointState;
</span><span class="cx"> 
</span><span class="lines">@@ -325,7 +333,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline void BreakingContext::handleBR(EClear&amp; clear)
</span><span class="cx"> {
</span><del>-    if (m_width.fitsOnLine()) {
</del><ins>+    if (fitsOnLineOrHangsAtEnd()) {
</ins><span class="cx">         RenderObject* br = m_current.renderer();
</span><span class="cx">         m_lineBreakHistory.push([&amp;](InlineIterator&amp; modifyMe) {
</span><span class="cx">             modifyMe.moveToStartOf(br);
</span><span class="lines">@@ -509,8 +517,11 @@
</span><span class="cx">         } else
</span><span class="cx">             m_trailingObjects.appendBoxIfNeeded(&amp;flowBox);
</span><span class="cx">     }
</span><del>-
-    m_width.addUncommittedWidth(inlineLogicalWidth(m_current.renderer()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));
</del><ins>+    
+    float inlineWidth = inlineLogicalWidth(m_current.renderer()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox);
+    m_width.addUncommittedWidth(inlineWidth);
+    if (m_hangsAtEnd &amp;&amp; inlineWidth)
+        m_hangsAtEnd = false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void BreakingContext::handleReplaced()
</span><span class="lines">@@ -530,7 +541,8 @@
</span><span class="cx">             m_atEnd = true;
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-    }
</del><ins>+    } else
+        m_hangsAtEnd = false;
</ins><span class="cx">     
</span><span class="cx">     if (replacedBox.isAnonymousInlineBlock())
</span><span class="cx">         m_block.layoutBlockChild(replacedBox, m_lineLayoutState.marginInfo(),
</span><span class="lines">@@ -706,6 +718,33 @@
</span><span class="cx">     hyphenated = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline float BreakingContext::computeAdditionalBetweenWordsWidth(RenderText&amp; renderText, TextLayout* textLayout, UChar currentCharacter, WordTrailingSpace&amp; wordTrailingSpace, HashSet&lt;const Font*&gt;&amp; fallbackFonts, WordMeasurements&amp; wordMeasurements, const FontCascade&amp; font, bool isFixedPitch, unsigned lastSpace, float lastSpaceWordSpacing, float wordSpacingForWordMeasurement, unsigned offset)
+{
+    wordMeasurements.grow(wordMeasurements.size() + 1);
+    WordMeasurement&amp; wordMeasurement = wordMeasurements.last();
+    
+    wordMeasurement.renderer = &amp;renderText;
+    wordMeasurement.endOffset = offset;
+    wordMeasurement.startOffset = lastSpace;
+    
+    float additionalTempWidth = 0;
+    WTF::Optional&lt;float&gt; wordTrailingSpaceWidth;
+    if (currentCharacter == ' ')
+        wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
+    if (wordTrailingSpaceWidth)
+        additionalTempWidth = textWidth(renderText, lastSpace, offset + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth.value();
+    else
+        additionalTempWidth = textWidth(renderText, lastSpace, offset - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
+    
+    if (wordMeasurement.fallbackFonts.isEmpty() &amp;&amp; !fallbackFonts.isEmpty())
+        wordMeasurement.fallbackFonts.swap(fallbackFonts);
+    fallbackFonts.clear();
+    
+    wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement;
+    additionalTempWidth += lastSpaceWordSpacing;
+    return additionalTempWidth;
+}
+
</ins><span class="cx"> inline bool BreakingContext::handleText(WordMeasurements&amp; wordMeasurements, bool&amp; hyphenated,  unsigned&amp; consecutiveHyphenatedLines)
</span><span class="cx"> {
</span><span class="cx">     if (!m_current.offset())
</span><span class="lines">@@ -737,6 +776,7 @@
</span><span class="cx">     bool canHyphenate = style.hyphens() == HyphensAuto &amp;&amp; WebCore::canHyphenate(style.locale());
</span><span class="cx">     bool canHangPunctuationAtStart = style.hangingPunctuation() &amp; FirstHangingPunctuation;
</span><span class="cx">     bool canHangPunctuationAtEnd = style.hangingPunctuation() &amp; LastHangingPunctuation;
</span><ins>+    bool canHangStopOrCommaAtLineEnd = style.hangingPunctuation() &amp; AllowEndHangingPunctuation;
</ins><span class="cx">     int endPunctuationIndex = canHangPunctuationAtEnd &amp;&amp; m_collapseWhiteSpace ? renderText.lastCharacterIndexStrippingSpaces() : renderText.textLength() - 1;
</span><span class="cx">     unsigned lastSpace = m_current.offset();
</span><span class="cx">     float wordSpacing = m_currentStyle-&gt;fontCascade().wordSpacing();
</span><span class="lines">@@ -794,7 +834,7 @@
</span><span class="cx">         
</span><span class="cx">         if (canHangPunctuationAtEnd &amp;&amp; !m_nextObject &amp;&amp; (int)m_current.offset() == endPunctuationIndex &amp;&amp; !inlineLogicalWidth(m_current.renderer(), false, true)) {
</span><span class="cx">             m_width.addUncommittedWidth(-renderText.hangablePunctuationEndWidth(endPunctuationIndex));
</span><del>-            canHangPunctuationAtStart = false;
</del><ins>+            canHangPunctuationAtEnd = false;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace)
</span><span class="lines">@@ -820,14 +860,30 @@
</span><span class="cx">         bool betweenWords = c == '\n' || (m_currWS != PRE &amp;&amp; !m_atStart &amp;&amp; isBreakable(m_renderTextInfo.lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, isLooseCJKMode, keepAllWords)
</span><span class="cx">             &amp;&amp; (style.hyphens() != HyphensNone || (m_current.previousInSameNode() != softHyphen)));
</span><span class="cx">         m_current.setNextBreakablePosition(nextBreakablePosition);
</span><del>-
</del><ins>+        
+        if (canHangStopOrCommaAtLineEnd &amp;&amp; renderText.isHangableStopOrComma(c) &amp;&amp; m_width.fitsOnLine()) {
+            // We need to see if a measurement that excludes the stop would fit. If so, then we should hang
+            // the stop/comma at the end. First measure including the comma.
+            m_hangsAtEnd = false;
+            float inlineStartWidth = !m_appliedStartWidth ? inlineLogicalWidth(m_current.renderer(), true, false) : LayoutUnit();
+            float widthIncludingComma = computeAdditionalBetweenWordsWidth(renderText, textLayout, c, wordTrailingSpace, fallbackFonts, wordMeasurements, font, isFixedPitch, lastSpace, lastSpaceWordSpacing, wordSpacingForWordMeasurement, m_current.offset() + 1) + inlineStartWidth;
+            m_width.addUncommittedWidth(widthIncludingComma);
+            if (!m_width.fitsOnLine()) {
+                // See if we fit without the comma involved. If we do, then this is a potential hang point.
+                float widthWithoutStopOrComma = computeAdditionalBetweenWordsWidth(renderText, textLayout, lastCharacter, wordTrailingSpace, fallbackFonts, wordMeasurements, font, isFixedPitch, lastSpace, lastSpaceWordSpacing, wordSpacingForWordMeasurement, m_current.offset()) + inlineStartWidth;
+                m_width.addUncommittedWidth(widthWithoutStopOrComma - widthIncludingComma);
+                if (m_width.fitsOnLine())
+                    m_hangsAtEnd = true;
+            } else
+                m_width.addUncommittedWidth(-widthIncludingComma);
+        }
+        
</ins><span class="cx">         if (betweenWords || midWordBreak) {
</span><span class="cx">             bool stoppedIgnoringSpaces = false;
</span><span class="cx">             if (m_ignoringSpaces) {
</span><span class="cx">                 lastSpaceWordSpacing = 0;
</span><span class="cx">                 if (!m_currentCharacterIsSpace) {
</span><del>-                    // Stop ignoring spaces and begin at this
-                    // new point.
</del><ins>+                    // Stop ignoring spaces and begin at this new point.
</ins><span class="cx">                     m_ignoringSpaces = false;
</span><span class="cx">                     wordSpacingForWordMeasurement = 0;
</span><span class="cx">                     lastSpace = m_current.offset(); // e.g., &quot;Foo    goo&quot;, don't add in any of the ignored spaces.
</span><span class="lines">@@ -839,51 +895,33 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 }
</span><span class="cx">             }
</span><del>-
-            wordMeasurements.grow(wordMeasurements.size() + 1);
</del><ins>+            
+            float additionalTempWidth = computeAdditionalBetweenWordsWidth(renderText, textLayout, c, wordTrailingSpace, fallbackFonts, wordMeasurements, font, isFixedPitch, lastSpace, lastSpaceWordSpacing, wordSpacingForWordMeasurement, m_current.offset());
+            m_width.addUncommittedWidth(additionalTempWidth);
+            
</ins><span class="cx">             WordMeasurement&amp; wordMeasurement = wordMeasurements.last();
</span><span class="cx"> 
</span><del>-            wordMeasurement.renderer = &amp;renderText;
-            wordMeasurement.endOffset = m_current.offset();
-            wordMeasurement.startOffset = lastSpace;
-
-            float additionalTempWidth;
-            WTF::Optional&lt;float&gt; wordTrailingSpaceWidth;
-            if (c == ' ')
-                wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
-            if (wordTrailingSpaceWidth) {
-                additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace,
-                    wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth.value();
-            }
-            else
-                additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
-
-            if (wordMeasurement.fallbackFonts.isEmpty() &amp;&amp; !fallbackFonts.isEmpty())
-                wordMeasurement.fallbackFonts.swap(fallbackFonts);
-            fallbackFonts.clear();
-
-            wordMeasurement.width = additionalTempWidth + wordSpacingForWordMeasurement;
-            additionalTempWidth += lastSpaceWordSpacing;
-            m_width.addUncommittedWidth(additionalTempWidth);
-
</del><span class="cx">             if (m_collapseWhiteSpace &amp;&amp; previousCharacterIsSpace &amp;&amp; m_currentCharacterIsSpace &amp;&amp; additionalTempWidth)
</span><span class="cx">                 m_width.setTrailingWhitespaceWidth(additionalTempWidth);
</span><span class="cx"> 
</span><span class="cx">             if (!m_appliedStartWidth) {
</span><del>-                m_width.addUncommittedWidth(inlineLogicalWidth(m_current.renderer(), true, false));
</del><ins>+                float inlineStartWidth = inlineLogicalWidth(m_current.renderer(), true, false);
+                m_width.addUncommittedWidth(inlineStartWidth);
</ins><span class="cx">                 m_appliedStartWidth = true;
</span><ins>+                if (m_hangsAtEnd &amp;&amp; inlineStartWidth)
+                    m_hangsAtEnd = false;
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             applyWordSpacing = wordSpacing &amp;&amp; m_currentCharacterIsSpace;
</span><span class="cx"> 
</span><del>-            if (!m_width.hasCommitted() &amp;&amp; m_autoWrap &amp;&amp; !m_width.fitsOnLine())
</del><ins>+            if (!m_width.hasCommitted() &amp;&amp; m_autoWrap &amp;&amp; !fitsOnLineOrHangsAtEnd())
</ins><span class="cx">                 m_width.fitBelowFloats(m_lineInfo.isFirstLine());
</span><span class="cx"> 
</span><span class="cx">             if (m_autoWrap || breakWords) {
</span><span class="cx">                 // If we break only after white-space, consider the current character
</span><span class="cx">                 // as candidate width for this line.
</span><span class="cx">                 bool lineWasTooWide = false;
</span><del>-                if (m_width.fitsOnLine() &amp;&amp; m_currentCharacterIsWS &amp;&amp; m_currentStyle-&gt;breakOnlyAfterWhiteSpace() &amp;&amp; !midWordBreak) {
</del><ins>+                if (fitsOnLineOrHangsAtEnd() &amp;&amp; m_currentCharacterIsWS &amp;&amp; m_currentStyle-&gt;breakOnlyAfterWhiteSpace() &amp;&amp; !midWordBreak) {
</ins><span class="cx">                     float charWidth = textWidth(renderText, m_current.offset(), 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
</span><span class="cx">                     // Check if line is too big even without the extra space
</span><span class="cx">                     // at the end of the line. If it is not, do nothing.
</span><span class="lines">@@ -898,7 +936,7 @@
</span><span class="cx">                         });
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><del>-                if (lineWasTooWide || !m_width.fitsOnLine()) {
</del><ins>+                if ((lineWasTooWide || !m_width.fitsOnLine()) &amp;&amp; !m_hangsAtEnd) {
</ins><span class="cx">                     if (canHyphenate &amp;&amp; !m_width.fitsOnLine()) {
</span><span class="cx">                         m_lineBreakHistory.push([&amp;](InlineIterator&amp; modifyMe) {
</span><span class="cx">                             tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, modifyMe, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
</span><span class="lines">@@ -1007,14 +1045,17 @@
</span><span class="cx">                     m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
</span><span class="cx">                 }
</span><span class="cx">             }
</span><del>-        } else if (m_ignoringSpaces) {
-            // Stop ignoring spaces and begin at this
-            // new point.
-            m_ignoringSpaces = false;
-            lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
-            wordSpacingForWordMeasurement = (applyWordSpacing &amp;&amp; wordMeasurements.last().width) ? wordSpacing : 0;
-            lastSpace = m_current.offset(); // e.g., &quot;Foo    goo&quot;, don't add in any of the ignored spaces.
-            m_lineMidpointState.stopIgnoringSpaces(InlineIterator(nullptr, m_current.renderer(), m_current.offset()));
</del><ins>+        } else {
+            if (m_ignoringSpaces) {
+                // Stop ignoring spaces and begin at this new point.
+                m_ignoringSpaces = false;
+                lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
+                wordSpacingForWordMeasurement = (applyWordSpacing &amp;&amp; wordMeasurements.last().width) ? wordSpacing : 0;
+                lastSpace = m_current.offset(); // e.g., &quot;Foo    goo&quot;, don't add in any of the ignored spaces.
+                m_lineMidpointState.stopIgnoringSpaces(InlineIterator(nullptr, m_current.renderer(), m_current.offset()));
+            }
+            if (m_hangsAtEnd &amp;&amp; !renderText.isHangableStopOrComma(c))
+                m_hangsAtEnd = false;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (isSVGText &amp;&amp; m_current.offset()) {
</span><span class="lines">@@ -1066,6 +1107,8 @@
</span><span class="cx"> 
</span><span class="cx">     float inlineLogicalTempWidth = inlineLogicalWidth(m_current.renderer(), !m_appliedStartWidth, m_includeEndWidth);
</span><span class="cx">     m_width.addUncommittedWidth(additionalTempWidth + inlineLogicalTempWidth);
</span><ins>+    if (m_hangsAtEnd &amp;&amp; inlineLogicalTempWidth)
+        m_hangsAtEnd = false;
</ins><span class="cx"> 
</span><span class="cx">     if (wordMeasurement.fallbackFonts.isEmpty() &amp;&amp; !fallbackFonts.isEmpty())
</span><span class="cx">         wordMeasurement.fallbackFonts.swap(fallbackFonts);
</span><span class="lines">@@ -1076,7 +1119,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_includeEndWidth = false;
</span><span class="cx"> 
</span><del>-    if (!m_width.fitsOnLine()) {
</del><ins>+    if (!fitsOnLineOrHangsAtEnd()) {
</ins><span class="cx">         if (canHyphenate) {
</span><span class="cx">             m_lineBreakHistory.push([&amp;](InlineIterator&amp; modifyMe) {
</span><span class="cx">                 tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, modifyMe, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
</span><span class="lines">@@ -1144,7 +1187,7 @@
</span><span class="cx"> {
</span><span class="cx">     bool checkForBreak = canBreakAtThisPosition();
</span><span class="cx"> 
</span><del>-    if (checkForBreak &amp;&amp; !m_width.fitsOnLine(m_ignoringSpaces)) {
</del><ins>+    if (checkForBreak &amp;&amp; !m_width.fitsOnLine(m_ignoringSpaces) &amp;&amp; !m_hangsAtEnd) {
</ins><span class="cx">         // if we have floats, try to get below them.
</span><span class="cx">         if (m_currentCharacterIsSpace &amp;&amp; !m_ignoringSpaces &amp;&amp; m_currentStyle-&gt;collapseWhiteSpace())
</span><span class="cx">             m_trailingObjects.clear();
</span><span class="lines">@@ -1154,7 +1197,8 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        m_width.fitBelowFloats(m_lineInfo.isFirstLine());
</del><ins>+        if (!m_hangsAtEnd)
+            m_width.fitBelowFloats(m_lineInfo.isFirstLine());
</ins><span class="cx"> 
</span><span class="cx">         // |width| may have been adjusted because we got shoved down past a float (thus
</span><span class="cx">         // giving us more room), so we need to retest, and only jump to
</span><span class="lines">@@ -1163,7 +1207,7 @@
</span><span class="cx">             m_atEnd = true;
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-    } else if (m_blockStyle.autoWrap() &amp;&amp; !m_width.fitsOnLine() &amp;&amp; !m_width.hasCommitted()) {
</del><ins>+    } else if (m_blockStyle.autoWrap() &amp;&amp; !m_width.fitsOnLine() &amp;&amp; !m_width.hasCommitted() &amp;&amp; !m_hangsAtEnd) {
</ins><span class="cx">         // If the container autowraps but the current child does not then we still need to ensure that it
</span><span class="cx">         // wraps and moves below any floats.
</span><span class="cx">         m_width.fitBelowFloats(m_lineInfo.isFirstLine());
</span></span></pre>
</div>
</div>

</body>
</html>