<!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>[197464] 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/197464">197464</a></dd>
<dt>Author</dt> <dd>hyatt@apple.com</dd>
<dt>Date</dt> <dd>2016-03-02 14:29:26 -0800 (Wed, 02 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add support for the &quot;first&quot; value of the hanging-punctuation property.
https://bugs.webkit.org/show_bug.cgi?id=154919

Reviewed by Simon Fraser.

Source/WebCore:

New tests added in fast/text.

Implement the &quot;first&quot; value for hanging-punctuation as described here:
https://drafts.csswg.org/css-text-3/#propdef-hanging-punctuation

* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::computeInlinePreferredLogicalWidths):
Update the preferred logical width computation to factor in hanging punctuation.
This check is similar to the text-indent logic in that we only want to do it for
the first formatted line.

* rendering/RenderBlockFlow.h:
(WebCore::RenderBlockFlow::simpleLineLayout):
Make sure to turn off simple line layout when hanging punctuation is present. Eventually
it should be feasible to support this in simple line layout, but since the full line
layout model has to work with it anyway, we are starting there.

* rendering/RenderBlockLineLayout.cpp:
(WebCore::inlineAncestorHasStartBorderPaddingOrMargin):
(WebCore::isLastInFlowRun):
Helper functions that are needed to determine whether or not we're allowed to apply
hanging punctuation &quot;first&quot; to a text run.

(WebCore::RenderBlockFlow::computeInlineDirectionPositionsForSegment):
This function manipulates logicalLeft and availableWidth when hanging punctuation
is present to shift the line as needed and to expand the availableWidth of the line.

* rendering/RenderText.cpp:
(WebCore::isHangablePunctuationAtLineStart):
(WebCore::isHangablePunctuationAtLineEnd):
(WebCore::RenderText::hangablePunctuationStartWidth):
(WebCore::RenderText::trimmedPrefWidths):
* rendering/RenderText.h:
RenderText has a helper function for handing back the hangable punctuation width. This
is used everywhere line layout wants to apply that offset. There are also helper functions
that detect whether the character is a hangable punctuation character.

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::canUseForWithReason):
(WebCore::SimpleLineLayout::printReason):
Turn off simple line layout when hanging punctuation is enabled.

* rendering/line/BreakingContext.h:
(WebCore::BreakingContext::handleText):
Modified to expand the available width when hanging punctuation is present so that we
know we have more room on the line.

* rendering/line/LineWidth.h:
(WebCore::LineWidth::isFirstLine):
Add an accessor for whether or not we're the first line.

LayoutTests:

* fast/text/hanging-punctuation-first-expected.html: Added.
* fast/text/hanging-punctuation-first-rtl-expected.html: Added.
* fast/text/hanging-punctuation-first-rtl.html: Added.
* fast/text/hanging-punctuation-first.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="#trunkSourceWebCorerenderingRenderBlockFlowcpp">trunk/Source/WebCore/rendering/RenderBlockFlow.cpp</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="#trunkSourceWebCorerenderingSimpleLineLayoutcpp">trunk/Source/WebCore/rendering/SimpleLineLayout.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderinglineBreakingContexth">trunk/Source/WebCore/rendering/line/BreakingContext.h</a></li>
<li><a href="#trunkSourceWebCorerenderinglineLineWidthh">trunk/Source/WebCore/rendering/line/LineWidth.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationfirstexpectedhtml">trunk/LayoutTests/fast/text/hanging-punctuation-first-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationfirstrtlexpectedhtml">trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl-expected.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationfirstrtlhtml">trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl.html</a></li>
<li><a href="#trunkLayoutTestsfasttexthangingpunctuationfirsthtml">trunk/LayoutTests/fast/text/hanging-punctuation-first.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/LayoutTests/ChangeLog        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-03-02  Dave Hyatt  &lt;hyatt@apple.com&gt;
+
+        Add support for the &quot;first&quot; value of the hanging-punctuation property.
+        https://bugs.webkit.org/show_bug.cgi?id=154919
+
+        Reviewed by Simon Fraser.
+
+        * fast/text/hanging-punctuation-first-expected.html: Added.
+        * fast/text/hanging-punctuation-first-rtl-expected.html: Added.
+        * fast/text/hanging-punctuation-first-rtl.html: Added.
+        * fast/text/hanging-punctuation-first.html: Added.
+
</ins><span class="cx"> 2016-03-01  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Make HTML parser construct custom elements
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationfirstexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-first-expected.html (0 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-first-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-first-expected.html        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+&lt;head&gt;
+&lt;style&gt;
+    body { font-family: 'Ahem'; color:green }
+    .hang { text-indent: -1em; margin:1em }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;float:left&quot; class=&quot;hang&quot;&gt;(Hang test)&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;(This should hang.&lt;br&gt;(This should not.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;(This should hang and justifybecause and now were fine.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;&lt;span&gt;(&lt;/span&gt;This should hang.&lt;/div&gt;
+&lt;div style=&quot;margin-left:1em; text-align:justify; width:300px;&quot;&gt;&lt;span style=&quot;border-left:1em solid blue&quot;&gt;(&lt;/span&gt;This should not hang.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-indent:1em; text-align:justify; width:300px;&quot;&gt;(This should hang into the text-indent.&lt;/div&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationfirstrtlexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl-expected.html (0 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl-expected.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl-expected.html        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+&lt;head&gt;
+&lt;style&gt;
+    body { font-family: 'Ahem'; color:green }
+    .hang { text-indent: -1em; margin:1em }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body style=&quot;direction:rtl&quot;&gt;
+&lt;div style=&quot;float:right&quot; class=&quot;hang&quot;&gt;(Hang test)&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;(This should hang.&lt;br&gt;(This should not.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;(This should hang and justifybecause and now were fine.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;&lt;span&gt;(&lt;/span&gt;This should hang.&lt;/div&gt;
+&lt;div style=&quot;margin-right:1em; text-align:justify; width:300px;&quot;&gt;&lt;span style=&quot;border-right:1em solid blue&quot;&gt;(&lt;/span&gt;This should not hang.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-indent:1em; text-align:justify; width:300px;&quot;&gt;(This should hang into the text-indent.&lt;/div&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationfirstrtlhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl.html (0 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-first-rtl.html        2016-03-02 22:29:26 UTC (rev 197464)
</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: first; margin:1em }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body style=&quot;direction:rtl&quot;&gt;
+&lt;div style=&quot;float:right&quot; class=&quot;hang&quot;&gt;(Hang test)&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;(This should hang.&lt;br&gt;(This should not.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;(This should hang and justifybecause and now were fine.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;&lt;span&gt;(&lt;/span&gt;This should hang.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;&lt;span style=&quot;border-right:1em solid blue&quot;&gt;(&lt;/span&gt;This should not hang.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-indent:2em; text-align:justify; width:300px;&quot;&gt;(This should hang into the text-indent.&lt;/div&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfasttexthangingpunctuationfirsthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/text/hanging-punctuation-first.html (0 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/hanging-punctuation-first.html                                (rev 0)
+++ trunk/LayoutTests/fast/text/hanging-punctuation-first.html        2016-03-02 22:29:26 UTC (rev 197464)
</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: first; margin:1em }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;float:left&quot; class=&quot;hang&quot;&gt;(Hang test)&lt;/div&gt;
+&lt;div style=&quot;clear:both&quot;&gt;
+&lt;div class=&quot;hang&quot;&gt;(This should hang.&lt;br&gt;(This should not.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;(This should hang and justifybecause and now were fine.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;&lt;span&gt;(&lt;/span&gt;This should hang.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-align:justify; width:300px;&quot;&gt;&lt;span style=&quot;border-left:1em solid blue&quot;&gt;(&lt;/span&gt;This should not hang.&lt;/div&gt;
+&lt;div class=&quot;hang&quot; style=&quot;text-indent:2em; text-align:justify; width:300px;&quot;&gt;(This should hang into the text-indent.&lt;/div&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/ChangeLog        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -1,3 +1,61 @@
</span><ins>+2016-03-02  Dave Hyatt  &lt;hyatt@apple.com&gt;
+
+        Add support for the &quot;first&quot; value of the hanging-punctuation property.
+        https://bugs.webkit.org/show_bug.cgi?id=154919
+
+        Reviewed by Simon Fraser.
+
+        New tests added in fast/text.
+
+        Implement the &quot;first&quot; value for hanging-punctuation as described here:
+        https://drafts.csswg.org/css-text-3/#propdef-hanging-punctuation
+
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::computeInlinePreferredLogicalWidths):
+        Update the preferred logical width computation to factor in hanging punctuation.
+        This check is similar to the text-indent logic in that we only want to do it for
+        the first formatted line.
+
+        * rendering/RenderBlockFlow.h:
+        (WebCore::RenderBlockFlow::simpleLineLayout):
+        Make sure to turn off simple line layout when hanging punctuation is present. Eventually
+        it should be feasible to support this in simple line layout, but since the full line
+        layout model has to work with it anyway, we are starting there.
+
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::inlineAncestorHasStartBorderPaddingOrMargin):
+        (WebCore::isLastInFlowRun):
+        Helper functions that are needed to determine whether or not we're allowed to apply
+        hanging punctuation &quot;first&quot; to a text run.
+
+        (WebCore::RenderBlockFlow::computeInlineDirectionPositionsForSegment):
+        This function manipulates logicalLeft and availableWidth when hanging punctuation
+        is present to shift the line as needed and to expand the availableWidth of the line.
+
+        * rendering/RenderText.cpp:
+        (WebCore::isHangablePunctuationAtLineStart):
+        (WebCore::isHangablePunctuationAtLineEnd):
+        (WebCore::RenderText::hangablePunctuationStartWidth):
+        (WebCore::RenderText::trimmedPrefWidths):
+        * rendering/RenderText.h:
+        RenderText has a helper function for handing back the hangable punctuation width. This
+        is used everywhere line layout wants to apply that offset. There are also helper functions
+        that detect whether the character is a hangable punctuation character.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::canUseForWithReason):
+        (WebCore::SimpleLineLayout::printReason):
+        Turn off simple line layout when hanging punctuation is enabled.
+
+        * rendering/line/BreakingContext.h:
+        (WebCore::BreakingContext::handleText):
+        Modified to expand the available width when hanging punctuation is present so that we
+        know we have more room on the line.
+
+        * rendering/line/LineWidth.h:
+        (WebCore::LineWidth::isFirstLine):
+        Add an accessor for whether or not we're the first line.
+
</ins><span class="cx"> 2016-03-01  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Make HTML parser construct custom elements
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderBlockFlowcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderBlockFlow.cpp (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderBlockFlow.cpp        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/RenderBlockFlow.cpp        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -4064,6 +4064,9 @@
</span><span class="cx">     RenderObject* prevFloat = 0;
</span><span class="cx">     bool isPrevChildInlineFlow = false;
</span><span class="cx">     bool shouldBreakLineAfterText = false;
</span><ins>+    bool canHangPunctuationAtStart = styleToUse.hangingPunctuation() &amp; FirstHangingPunctuation;
+    bool addedStartPunctuationHang = false;
+    
</ins><span class="cx">     while (RenderObject* child = childIterator.next()) {
</span><span class="cx">         bool autoWrap = child-&gt;isReplaced() ? child-&gt;parent()-&gt;style().autoWrap() :
</span><span class="cx">             child-&gt;style().autoWrap();
</span><span class="lines">@@ -4179,6 +4182,9 @@
</span><span class="cx">                     else
</span><span class="cx">                         addedTextIndent = true;
</span><span class="cx">                 }
</span><ins>+                
+                if (canHangPunctuationAtStart &amp;&amp; !addedStartPunctuationHang &amp;&amp; !child-&gt;isFloating() &amp;&amp; !isAnonymousInlineBlock)
+                    addedStartPunctuationHang = true;
</ins><span class="cx"> 
</span><span class="cx">                 // Add our width to the max.
</span><span class="cx">                 inlineMax += std::max&lt;float&gt;(0, childMax);
</span><span class="lines">@@ -4267,7 +4273,17 @@
</span><span class="cx">                         hasRemainingNegativeTextIndent = true;
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><del>-
</del><ins>+                
+                // See if we have a hanging punctuation situation at the start.
+                if (canHangPunctuationAtStart &amp;&amp; !addedStartPunctuationHang) {
+                    float hangStartWidth = renderText.hangablePunctuationStartWidth();
+                    childMin -= hangStartWidth;
+                    beginMin -= hangStartWidth;
+                    childMax -= hangStartWidth;
+                    beginMax -= hangStartWidth;
+                    addedStartPunctuationHang = true;
+                }
+                
</ins><span class="cx">                 // If we have no breakable characters at all,
</span><span class="cx">                 // then this is the easy case. We add ourselves to the current
</span><span class="cx">                 // min and max and continue.
</span><span class="lines">@@ -4305,6 +4321,7 @@
</span><span class="cx">                     maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
</span><span class="cx">                     inlineMax = endMax;
</span><span class="cx">                     addedTextIndent = true;
</span><ins>+                    addedStartPunctuationHang = true;
</ins><span class="cx">                 } else
</span><span class="cx">                     inlineMax += std::max&lt;float&gt;(0, childMax);
</span><span class="cx">             }
</span><span class="lines">@@ -4319,6 +4336,7 @@
</span><span class="cx">             stripFrontSpaces = true;
</span><span class="cx">             trailingSpaceChild = 0;
</span><span class="cx">             addedTextIndent = true;
</span><ins>+            addedStartPunctuationHang = true;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (!child-&gt;isText() &amp;&amp; child-&gt;isRenderInline())
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderBlockLineLayoutcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -806,11 +806,34 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool inlineAncestorHasStartBorderPaddingOrMargin(const RenderBlockFlow&amp; block, const InlineBox&amp; box)
+{
+    bool isLTR = block.style().isLeftToRightDirection();
+    for (auto* currentBox = box.parent(); currentBox; currentBox = currentBox-&gt;parent()) {
+        if ((isLTR &amp;&amp; currentBox-&gt;marginBorderPaddingLogicalLeft() &gt; 0)
+            || (!isLTR &amp;&amp; currentBox-&gt;marginBorderPaddingLogicalRight() &gt; 0))
+            return true;
+    }
+    return false;
+}
+
+static bool isLastInFlowRun(BidiRun&amp; runToCheck)
+{
+    for (auto* run = runToCheck.next(); run; run = run-&gt;next()) {
+        if (!run-&gt;box() || run-&gt;renderer().isOutOfFlowPositioned() || run-&gt;box()-&gt;isLineBreak())
+            continue;
+        return false;
+    }
+    return true;
+}
+    
</ins><span class="cx"> BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo&amp; lineInfo, ETextAlign textAlign, float&amp; logicalLeft, 
</span><span class="cx">     float&amp; availableLogicalWidth, BidiRun* firstRun, BidiRun* trailingSpaceRun, GlyphOverflowAndFallbackFontsMap&amp; textBoxDataMap, VerticalPositionCache&amp; verticalPositionCache,
</span><span class="cx">     WordMeasurements&amp; wordMeasurements)
</span><span class="cx"> {
</span><span class="cx">     bool needsWordSpacing = false;
</span><ins>+    bool canHangPunctuationAtStart = style().hangingPunctuation() &amp; FirstHangingPunctuation;
+    bool isLTR = style().isLeftToRightDirection();
</ins><span class="cx">     float totalLogicalWidth = lineBox-&gt;getFlowSpacingLogicalWidth();
</span><span class="cx">     unsigned expansionOpportunityCount = 0;
</span><span class="cx">     bool isAfterExpansion = is&lt;RenderRubyBase&gt;(*this) ? downcast&lt;RenderRubyBase&gt;(*this).isAfterExpansion() : true;
</span><span class="lines">@@ -827,6 +850,15 @@
</span><span class="cx">         if (is&lt;RenderText&gt;(run-&gt;renderer())) {
</span><span class="cx">             auto&amp; renderText = downcast&lt;RenderText&gt;(run-&gt;renderer());
</span><span class="cx">             auto&amp; textBox = downcast&lt;InlineTextBox&gt;(*run-&gt;box());
</span><ins>+            if (canHangPunctuationAtStart &amp;&amp; lineInfo.isFirstLine() &amp;&amp; (isLTR || isLastInFlowRun(*run))
+                &amp;&amp; !inlineAncestorHasStartBorderPaddingOrMargin(*this, *run-&gt;box())) {
+                float hangStartWidth = renderText.hangablePunctuationStartWidth();
+                availableLogicalWidth += hangStartWidth;
+                if (style().isLeftToRightDirection())
+                    logicalLeft -= hangStartWidth;
+                canHangPunctuationAtStart = false;
+            }
+            
</ins><span class="cx">             if (textAlign == JUSTIFY &amp;&amp; run != trailingSpaceRun) {
</span><span class="cx">                 ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(*this, textBox, previousRun, run-&gt;next(), textAlign, isAfterExpansion);
</span><span class="cx">                 applyExpansionBehavior(textBox, expansionBehavior);
</span><span class="lines">@@ -844,6 +876,7 @@
</span><span class="cx"> 
</span><span class="cx">             setLogicalWidthForTextRun(lineBox, run, renderText, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
</span><span class="cx">         } else {
</span><ins>+            canHangPunctuationAtStart = false;
</ins><span class="cx">             bool encounteredJustifiedRuby = false;
</span><span class="cx">             if (is&lt;RenderRubyRun&gt;(run-&gt;renderer()) &amp;&amp; textAlign == JUSTIFY &amp;&amp; run != trailingSpaceRun &amp;&amp; downcast&lt;RenderRubyRun&gt;(run-&gt;renderer()).rubyBase()) {
</span><span class="cx">                 auto* rubyBase = downcast&lt;RenderRubyRun&gt;(run-&gt;renderer()).rubyBase();
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderTextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderText.cpp (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderText.cpp        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/RenderText.cpp        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -502,6 +502,32 @@
</span><span class="cx">     return f.width(run, fallbackFonts, glyphOverflow);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool isHangablePunctuationAtLineStart(UChar c)
+{
+    return U_GET_GC_MASK(c) &amp; (U_GC_PS_MASK | U_GC_PI_MASK | U_GC_PF_MASK);
+}
+
+inline bool isHangablePunctuationAtLineEnd(UChar c)
+{
+    return U_GET_GC_MASK(c) &amp; (U_GC_PE_MASK | U_GC_PI_MASK | U_GC_PF_MASK);
+}
+
+float RenderText::hangablePunctuationStartWidth() const
+{
+    if (!textLength())
+        return 0;
+    
+    ASSERT(m_text);
+    StringImpl&amp; text = *m_text.impl();
+    if (!isHangablePunctuationAtLineStart(text[0]))
+        return 0;
+    
+    const RenderStyle&amp; style = this-&gt;style();
+    const FontCascade&amp; font = style.fontCascade();
+        
+    return widthFromCache(font, 0, 1, 0, 0, 0, style);
+}
+    
</ins><span class="cx"> void RenderText::trimmedPrefWidths(float leadWidth,
</span><span class="cx">                                    float&amp; beginMinW, bool&amp; beginWS,
</span><span class="cx">                                    float&amp; endMinW, bool&amp; endWS,
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderTexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderText.h (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderText.h        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/RenderText.h        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -102,6 +102,7 @@
</span><span class="cx">                            bool&amp; hasBreakableChar, bool&amp; hasBreak,
</span><span class="cx">                            float&amp; beginMaxW, float&amp; endMaxW,
</span><span class="cx">                            float&amp; minW, float&amp; maxW, bool&amp; stripFrontSpaces);
</span><ins>+    float hangablePunctuationStartWidth() const;
</ins><span class="cx"> 
</span><span class="cx">     WEBCORE_EXPORT virtual IntRect linesBoundingBox() const;
</span><span class="cx">     LayoutRect linesVisualOverflowBoundingBox() const;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingSimpleLineLayoutcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -111,7 +111,8 @@
</span><span class="cx">     FlowHasNoParent                       = 1LLU  &lt;&lt; 46,
</span><span class="cx">     FlowHasNoChild                        = 1LLU  &lt;&lt; 47,
</span><span class="cx">     FlowChildIsSelected                   = 1LLU  &lt;&lt; 48,
</span><del>-    EndOfReasons                          = 1LLU  &lt;&lt; 49
</del><ins>+    FlowHasHangingPunctuation             = 1LLU  &lt;&lt; 49,
+    EndOfReasons                          = 1LLU  &lt;&lt; 50
</ins><span class="cx"> };
</span><span class="cx"> const unsigned NoReason = 0;
</span><span class="cx"> 
</span><span class="lines">@@ -283,6 +284,9 @@
</span><span class="cx">         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasOutline, reasons, includeReasons);
</span><span class="cx">     if (flow.isRubyText() || flow.isRubyBase())
</span><span class="cx">         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsRuby, reasons, includeReasons);
</span><ins>+    if (flow.style().hangingPunctuation() != NoHangingPunctuation)
+        SET_REASON_AND_RETURN_IF_NEEDED(FlowHasHangingPunctuation, reasons, includeReasons);
+    
</ins><span class="cx">     // Printing does pagination without a flow thread.
</span><span class="cx">     if (flow.document().paginated())
</span><span class="cx">         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsPaginated, reasons, includeReasons);
</span><span class="lines">@@ -798,6 +802,9 @@
</span><span class="cx">     case FlowIsRuby:
</span><span class="cx">         stream &lt;&lt; &quot;ruby&quot;;
</span><span class="cx">         break;
</span><ins>+    case FlowHasHangingPunctuation:
+        stream &lt;&lt; &quot;hanging punctuation&quot;;
+        break;
</ins><span class="cx">     case FlowIsPaginated:
</span><span class="cx">         stream &lt;&lt; &quot;paginated&quot;;
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderinglineBreakingContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/line/BreakingContext.h (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/line/BreakingContext.h        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/line/BreakingContext.h        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -737,7 +737,8 @@
</span><span class="cx">     const FontCascade&amp; font = style.fontCascade();
</span><span class="cx">     bool isFixedPitch = font.isFixedPitch();
</span><span class="cx">     bool canHyphenate = style.hyphens() == HyphensAuto &amp;&amp; WebCore::canHyphenate(style.locale());
</span><del>-
</del><ins>+    bool canHangPunctuationAtStart = style.hangingPunctuation() &amp; FirstHangingPunctuation;
+    
</ins><span class="cx">     unsigned lastSpace = m_current.offset();
</span><span class="cx">     float wordSpacing = m_currentStyle-&gt;fontCascade().wordSpacing();
</span><span class="cx">     float lastSpaceWordSpacing = 0;
</span><span class="lines">@@ -787,6 +788,9 @@
</span><span class="cx">         UChar c = m_current.current();
</span><span class="cx">         m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline &amp;&amp; (c == '\n'));
</span><span class="cx"> 
</span><ins>+        if (canHangPunctuationAtStart &amp;&amp; !m_current.offset() &amp;&amp; m_width.isFirstLine() &amp;&amp; !m_width.committedWidth() &amp;&amp; !wrapW &amp;&amp; !m_current.offset())
+            m_width.addUncommittedWidth(-renderText.hangablePunctuationStartWidth());
+            
</ins><span class="cx">         if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace)
</span><span class="cx">             m_lineInfo.setEmpty(false, &amp;m_block, &amp;m_width);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderinglineLineWidthh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/line/LineWidth.h (197463 => 197464)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/line/LineWidth.h        2016-03-02 21:56:47 UTC (rev 197463)
+++ trunk/Source/WebCore/rendering/line/LineWidth.h        2016-03-02 22:29:26 UTC (rev 197464)
</span><span class="lines">@@ -77,6 +77,8 @@
</span><span class="cx">     void fitBelowFloats(bool isFirstLine = false);
</span><span class="cx">     void setTrailingWhitespaceWidth(float collapsedWhitespace, float borderPaddingMargin = 0);
</span><span class="cx">     IndentTextOrNot shouldIndentText() const { return m_shouldIndentText; }
</span><ins>+    
+    bool isFirstLine() const { return m_isFirstLine; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     void computeAvailableWidthFromLeftAndRight();
</span></span></pre>
</div>
</div>

</body>
</html>