<!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>[211382] 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/211382">211382</a></dd>
<dt>Author</dt> <dd>mmaxfield@apple.com</dd>
<dt>Date</dt> <dd>2017-01-30 12:43:14 -0800 (Mon, 30 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Correct spacing regression on inter-element complex path shaping on some fonts
https://bugs.webkit.org/show_bug.cgi?id=166013

Reviewed by Simon Fraser.

Source/WebCore:

This patch brings the implementation of ComplexTextController in-line with the
design at https://trac.webkit.org/wiki/ComplexTextController. Previously,
ComplexTextController had a few problems:
- The total width computed by ComplexTextController didn't match the width if
you iterated over the entire string and added up the advances
- FontCascade::getGlyphsAndAdvancesForComplexText() tried to compensate for
the above by construing the concepts of paint advances as distinct from layout
advances
- Initial advances were considered part of layout sometimes and part of painting
other times, depending on which function reports the information
- For RTL runs, the wrong origin was added to the initial advance, and the origin
should have been subtracted instead of added

This patch exhaustively updates every function in ComplexTextController to be
consistent with the design linked to above. This design solves all of these
problems.

Tests: ComplexTextControllerTest.InitialAdvanceWithLeftRunInRTL
       ComplexTextControllerTest.InitialAdvanceInRTL
       ComplexTextControllerTest.InitialAdvanceWithLeftRunInLTR
       ComplexTextControllerTest.InitialAdvanceInLTR
       ComplexTextControllerTest.InitialAdvanceInRTLNoOrigins
       ComplexTextControllerTest.LeadingExpansion
       ComplexTextControllerTest.VerticalAdvances

* platform/graphics/GlyphBuffer.h:
(WebCore::GlyphBuffer::setLeadingExpansion): Deleted. No longer necessary.
(WebCore::GlyphBuffer::leadingExpansion): Deleted. Ditto.
* platform/graphics/cocoa/FontCascadeCocoa.mm:
(WebCore::FontCascade::adjustSelectionRectForComplexText): Removed use of
unnecessary leadingExpansion().
(WebCore::FontCascade::getGlyphsAndAdvancesForComplexText): This function needs
to compute paint advances, which means that it can't base this information off
of layout advances. This function uses the trick mentioned at the end of the
above link to compute the paint offset of an arbitrary glyph in the middle of
an RTL run.
* platform/graphics/mac/ComplexTextController.cpp:
(WebCore::ComplexTextController::computeExpansionOpportunity): Refactored for
testing.
(WebCore::ComplexTextController::ComplexTextController): Ditto.
(WebCore::ComplexTextController::finishConstruction): Ditto.
(WebCore::ComplexTextController::offsetForPosition): This function operates on
layout advances, and the initial layout advance is already added into the
m_adjustedBaseAdvances vector by adjustGlyphsAndAdvances(). Therefore, there is
no need to add it again here.
(WebCore::ComplexTextController::advance): This function had completely busted
logic about the relationship between initial advances and the first origin in
each run. Because of the fortunate choice of only representing layout advances
in m_adjustedBaseAdvances, this entire block can be removed and the raw paint
initial advance can be reported to the GlyphBuffer. Later in the function, we
have to update the logic about how to compute a paint advance given a layout
advance and some origins. In particular, there are two tricky pieces here: 1.
The layout advance for the first glyph is equal to (initial advance - first
origin + first Core Text advance, so computing the paint offset must cancel out
the initial layout offset, and 2. the last paint advance in a run must actually
end up at the position of the first glyph in the next run, so the next run's
initial advance must be queried.
(WebCore::ComplexTextController::adjustGlyphsAndAdvances): Previously, we
represented an initial advance of a successive run by just adding it to the
previous run's last advance. However, this is incompatible with the new model
presented in the link above, so we remove this section. We also have to add in
the logic that the layout advance for the first glyph is equal to the formula
presented above.
* platform/graphics/mac/ComplexTextController.h:
(WebCore::ComplexTextController::ComplexTextRun::initialAdvance): Adjust comment
to reflect reality.
(WebCore::ComplexTextController::leadingExpansion): Deleted.

Tools:

Unskip existing tests and make some new tests:
- Testing complex text with no origins
- Testing initial expansions
- Testing the sign of vertical advances

* TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp:
(TestWebKitAPI::TEST_F):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGlyphBufferh">trunk/Source/WebCore/platform/graphics/GlyphBuffer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscocoaFontCascadeCocoamm">trunk/Source/WebCore/platform/graphics/cocoa/FontCascadeCocoa.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsmacComplexTextControllercpp">trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsmacComplexTextControllerh">trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCoreComplexTextControllercpp">trunk/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Source/WebCore/ChangeLog        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -1,3 +1,78 @@
</span><ins>+2017-01-30  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Correct spacing regression on inter-element complex path shaping on some fonts
+        https://bugs.webkit.org/show_bug.cgi?id=166013
+
+        Reviewed by Simon Fraser.
+
+        This patch brings the implementation of ComplexTextController in-line with the
+        design at https://trac.webkit.org/wiki/ComplexTextController. Previously,
+        ComplexTextController had a few problems:
+        - The total width computed by ComplexTextController didn't match the width if
+        you iterated over the entire string and added up the advances
+        - FontCascade::getGlyphsAndAdvancesForComplexText() tried to compensate for
+        the above by construing the concepts of paint advances as distinct from layout
+        advances
+        - Initial advances were considered part of layout sometimes and part of painting
+        other times, depending on which function reports the information
+        - For RTL runs, the wrong origin was added to the initial advance, and the origin
+        should have been subtracted instead of added
+
+        This patch exhaustively updates every function in ComplexTextController to be
+        consistent with the design linked to above. This design solves all of these
+        problems.
+
+        Tests: ComplexTextControllerTest.InitialAdvanceWithLeftRunInRTL
+               ComplexTextControllerTest.InitialAdvanceInRTL
+               ComplexTextControllerTest.InitialAdvanceWithLeftRunInLTR
+               ComplexTextControllerTest.InitialAdvanceInLTR
+               ComplexTextControllerTest.InitialAdvanceInRTLNoOrigins
+               ComplexTextControllerTest.LeadingExpansion
+               ComplexTextControllerTest.VerticalAdvances
+
+        * platform/graphics/GlyphBuffer.h:
+        (WebCore::GlyphBuffer::setLeadingExpansion): Deleted. No longer necessary.
+        (WebCore::GlyphBuffer::leadingExpansion): Deleted. Ditto.
+        * platform/graphics/cocoa/FontCascadeCocoa.mm:
+        (WebCore::FontCascade::adjustSelectionRectForComplexText): Removed use of
+        unnecessary leadingExpansion().
+        (WebCore::FontCascade::getGlyphsAndAdvancesForComplexText): This function needs
+        to compute paint advances, which means that it can't base this information off
+        of layout advances. This function uses the trick mentioned at the end of the
+        above link to compute the paint offset of an arbitrary glyph in the middle of
+        an RTL run.
+        * platform/graphics/mac/ComplexTextController.cpp:
+        (WebCore::ComplexTextController::computeExpansionOpportunity): Refactored for
+        testing.
+        (WebCore::ComplexTextController::ComplexTextController): Ditto.
+        (WebCore::ComplexTextController::finishConstruction): Ditto.
+        (WebCore::ComplexTextController::offsetForPosition): This function operates on
+        layout advances, and the initial layout advance is already added into the
+        m_adjustedBaseAdvances vector by adjustGlyphsAndAdvances(). Therefore, there is
+        no need to add it again here.
+        (WebCore::ComplexTextController::advance): This function had completely busted
+        logic about the relationship between initial advances and the first origin in
+        each run. Because of the fortunate choice of only representing layout advances 
+        in m_adjustedBaseAdvances, this entire block can be removed and the raw paint
+        initial advance can be reported to the GlyphBuffer. Later in the function, we
+        have to update the logic about how to compute a paint advance given a layout
+        advance and some origins. In particular, there are two tricky pieces here: 1.
+        The layout advance for the first glyph is equal to (initial advance - first
+        origin + first Core Text advance, so computing the paint offset must cancel out
+        the initial layout offset, and 2. the last paint advance in a run must actually
+        end up at the position of the first glyph in the next run, so the next run's
+        initial advance must be queried.
+        (WebCore::ComplexTextController::adjustGlyphsAndAdvances): Previously, we
+        represented an initial advance of a successive run by just adding it to the
+        previous run's last advance. However, this is incompatible with the new model
+        presented in the link above, so we remove this section. We also have to add in
+        the logic that the layout advance for the first glyph is equal to the formula
+        presented above.
+        * platform/graphics/mac/ComplexTextController.h:
+        (WebCore::ComplexTextController::ComplexTextRun::initialAdvance): Adjust comment
+        to reflect reality.
+        (WebCore::ComplexTextController::leadingExpansion): Deleted.
+
</ins><span class="cx"> 2017-01-30  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fixed elements should not rubber-band in WK2, nor remain at negative offsets
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGlyphBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/GlyphBuffer.h (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/GlyphBuffer.h        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Source/WebCore/platform/graphics/GlyphBuffer.h        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -102,9 +102,6 @@
</span><span class="cx"> 
</span><span class="cx">     void setInitialAdvance(GlyphBufferAdvance initialAdvance) { m_initialAdvance = initialAdvance; }
</span><span class="cx">     const GlyphBufferAdvance&amp; initialAdvance() const { return m_initialAdvance; }
</span><del>-
-    void setLeadingExpansion(float leadingExpansion) { m_leadingExpansion = leadingExpansion; }
-    float leadingExpansion() const { return m_leadingExpansion; }
</del><span class="cx">     
</span><span class="cx">     Glyph glyphAt(unsigned index) const
</span><span class="cx">     {
</span><span class="lines">@@ -248,7 +245,6 @@
</span><span class="cx"> #if PLATFORM(WIN)
</span><span class="cx">     Vector&lt;FloatSize, 2048&gt; m_offsets;
</span><span class="cx"> #endif
</span><del>-    float m_leadingExpansion;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscocoaFontCascadeCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cocoa/FontCascadeCocoa.mm (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cocoa/FontCascadeCocoa.mm        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Source/WebCore/platform/graphics/cocoa/FontCascadeCocoa.mm        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -497,7 +497,7 @@
</span><span class="cx">     float afterWidth = controller.runWidthSoFar();
</span><span class="cx"> 
</span><span class="cx">     if (run.rtl())
</span><del>-        selectionRect.move(controller.totalWidth() - afterWidth + controller.leadingExpansion(), 0);
</del><ins>+        selectionRect.move(controller.totalWidth() - afterWidth, 0);
</ins><span class="cx">     else
</span><span class="cx">         selectionRect.move(beforeWidth, 0);
</span><span class="cx">     selectionRect.setWidth(LayoutUnit::fromFloatCeil(afterWidth - beforeWidth));
</span><span class="lines">@@ -508,20 +508,25 @@
</span><span class="cx">     float initialAdvance;
</span><span class="cx"> 
</span><span class="cx">     ComplexTextController controller(*this, run, false, 0, forTextEmphasis);
</span><del>-    controller.advance(from);
-    float beforeWidth = controller.runWidthSoFar();
</del><ins>+    GlyphBuffer dummyGlyphBuffer;
+    controller.advance(from, &amp;dummyGlyphBuffer);
</ins><span class="cx">     controller.advance(to, &amp;glyphBuffer);
</span><span class="cx"> 
</span><span class="cx">     if (glyphBuffer.isEmpty())
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    float afterWidth = controller.runWidthSoFar();
-
</del><span class="cx">     if (run.rtl()) {
</span><del>-        initialAdvance = controller.totalWidth() - afterWidth + controller.leadingExpansion();
</del><ins>+        // Exploit the fact that the sum of the paint advances is equal to
+        // the sum of the layout advances.
+        initialAdvance = controller.totalWidth();
+        for (unsigned i = 0; i &lt; glyphBuffer.size(); ++i)
+            initialAdvance -= glyphBuffer.advanceAt(i).width();
</ins><span class="cx">         glyphBuffer.reverse(0, glyphBuffer.size());
</span><del>-    } else
-        initialAdvance = beforeWidth;
</del><ins>+    } else {
+        initialAdvance = dummyGlyphBuffer.initialAdvance().width();
+        for (unsigned i = 0; i &lt; dummyGlyphBuffer.size(); ++i)
+            initialAdvance += dummyGlyphBuffer.advanceAt(i).width();
+    }
</ins><span class="cx"> 
</span><span class="cx">     return initialAdvance;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsmacComplexTextControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -107,19 +107,12 @@
</span><span class="cx">     return layout.width(from, len, fallbackFonts);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ComplexTextController::ComplexTextController(const FontCascade&amp; font, const TextRun&amp; run, bool mayUseNaturalWritingDirection, HashSet&lt;const Font*&gt;* fallbackFonts, bool forTextEmphasis)
-    : m_fallbackFonts(fallbackFonts)
-    , m_font(font)
-    , m_run(run)
-    , m_end(run.length())
-    , m_expansion(run.expansion())
-    , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
-    , m_forTextEmphasis(forTextEmphasis)
</del><ins>+void ComplexTextController::computeExpansionOpportunity()
</ins><span class="cx"> {
</span><span class="cx">     if (!m_expansion)
</span><span class="cx">         m_expansionPerOpportunity = 0;
</span><span class="cx">     else {
</span><del>-        unsigned expansionOpportunityCount = FontCascade::expansionOpportunityCount(m_run.text(), m_run.ltr() ? LTR : RTL, run.expansionBehavior()).first;
</del><ins>+        unsigned expansionOpportunityCount = FontCascade::expansionOpportunityCount(m_run.text(), m_run.ltr() ? LTR : RTL, m_run.expansionBehavior()).first;
</ins><span class="cx"> 
</span><span class="cx">         if (!expansionOpportunityCount)
</span><span class="cx">             m_expansionPerOpportunity = 0;
</span><span class="lines">@@ -126,7 +119,19 @@
</span><span class="cx">         else
</span><span class="cx">             m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
</span><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><ins>+ComplexTextController::ComplexTextController(const FontCascade&amp; font, const TextRun&amp; run, bool mayUseNaturalWritingDirection, HashSet&lt;const Font*&gt;* fallbackFonts, bool forTextEmphasis)
+    : m_fallbackFonts(fallbackFonts)
+    , m_font(font)
+    , m_run(run)
+    , m_end(run.length())
+    , m_expansion(run.expansion())
+    , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
+    , m_forTextEmphasis(forTextEmphasis)
+{
+    computeExpansionOpportunity();
+
</ins><span class="cx">     collectComplexTextRuns();
</span><span class="cx"> 
</span><span class="cx">     finishConstruction();
</span><span class="lines">@@ -136,7 +141,10 @@
</span><span class="cx">     : m_font(font)
</span><span class="cx">     , m_run(run)
</span><span class="cx">     , m_end(run.length())
</span><ins>+    , m_expansion(run.expansion())
</ins><span class="cx"> {
</span><ins>+    computeExpansionOpportunity();
+
</ins><span class="cx">     for (auto&amp; run : runs)
</span><span class="cx">         m_complexTextRuns.append(run.ptr());
</span><span class="cx"> 
</span><span class="lines">@@ -157,8 +165,6 @@
</span><span class="cx">             glyphCountSoFar += m_complexTextRuns[i]-&gt;glyphCount();
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-
-    m_runWidthSoFar = m_leadingExpansion;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> unsigned ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
</span><span class="lines">@@ -166,7 +172,6 @@
</span><span class="cx">     if (h &gt;= m_totalWidth)
</span><span class="cx">         return m_run.ltr() ? m_end : 0;
</span><span class="cx"> 
</span><del>-    h -= m_leadingExpansion;
</del><span class="cx">     if (h &lt; 0)
</span><span class="cx">         return m_run.ltr() ? 0 : m_end;
</span><span class="cx"> 
</span><span class="lines">@@ -180,8 +185,6 @@
</span><span class="cx">         for (unsigned j = 0; j &lt; complexTextRun.glyphCount(); ++j) {
</span><span class="cx">             size_t index = offsetIntoAdjustedGlyphs + j;
</span><span class="cx">             CGFloat adjustedAdvance = m_adjustedBaseAdvances[index].width;
</span><del>-            if (!index)
-                adjustedAdvance += complexTextRun.initialAdvance().width;
</del><span class="cx">             if (x &lt; adjustedAdvance) {
</span><span class="cx">                 CFIndex hitGlyphStart = complexTextRun.indexAt(j);
</span><span class="cx">                 CFIndex hitGlyphEnd;
</span><span class="lines">@@ -561,7 +564,7 @@
</span><span class="cx">         offset = m_end;
</span><span class="cx"> 
</span><span class="cx">     if (offset &lt;= m_currentCharacter) {
</span><del>-        m_runWidthSoFar = m_leadingExpansion;
</del><ins>+        m_runWidthSoFar = 0;
</ins><span class="cx">         m_numGlyphsSoFar = 0;
</span><span class="cx">         m_currentRun = 0;
</span><span class="cx">         m_glyphInCurrentRun = 0;
</span><span class="lines">@@ -572,14 +575,14 @@
</span><span class="cx"> 
</span><span class="cx">     size_t runCount = m_complexTextRuns.size();
</span><span class="cx"> 
</span><del>-    unsigned leftmostGlyph = 0;
-    unsigned currentRunIndex = indexOfCurrentRun(leftmostGlyph);
</del><ins>+    unsigned indexOfLeftmostGlyphInCurrentRun = 0; // Relative to the beginning of ComplexTextController.
+    unsigned currentRunIndex = indexOfCurrentRun(indexOfLeftmostGlyphInCurrentRun);
</ins><span class="cx">     while (m_currentRun &lt; runCount) {
</span><span class="cx">         const ComplexTextRun&amp; complexTextRun = *m_complexTextRuns[currentRunIndex];
</span><span class="cx">         bool ltr = complexTextRun.isLTR();
</span><span class="cx">         size_t glyphCount = complexTextRun.glyphCount();
</span><del>-        unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
-        unsigned k = leftmostGlyph + g;
</del><ins>+        unsigned glyphIndexIntoCurrentRun = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
+        unsigned glyphIndexIntoComplexTextController = indexOfLeftmostGlyphInCurrentRun + glyphIndexIntoCurrentRun;
</ins><span class="cx">         if (fallbackFonts &amp;&amp; &amp;complexTextRun.font() != &amp;m_font.primaryFont())
</span><span class="cx">             fallbackFonts-&gt;add(&amp;complexTextRun.font());
</span><span class="cx"> 
</span><span class="lines">@@ -586,43 +589,45 @@
</span><span class="cx">         // We must store the initial advance for the first glyph we are going to draw.
</span><span class="cx">         // When leftmostGlyph is 0, it represents the first glyph to draw, taking into
</span><span class="cx">         // account the text direction.
</span><del>-        if (glyphBuffer &amp;&amp; !leftmostGlyph) {
-            CGSize initialAdvance = complexTextRun.initialAdvance();
-#if USE_LAYOUT_SPECIFIC_ADVANCES
-            unsigned index = ltr ? 0 : m_adjustedBaseAdvances.size() - 1;
-            initialAdvance.width += glyphOrigin(index).x;
-            initialAdvance.height += glyphOrigin(index).y;
-#endif
-            glyphBuffer-&gt;setInitialAdvance(initialAdvance);
</del><ins>+        if (!indexOfLeftmostGlyphInCurrentRun &amp;&amp; glyphBuffer)
+            glyphBuffer-&gt;setInitialAdvance(complexTextRun.initialAdvance());
</ins><span class="cx"> 
</span><del>-            glyphBuffer-&gt;setLeadingExpansion(m_leadingExpansion);
-        }
-
</del><span class="cx">         while (m_glyphInCurrentRun &lt; glyphCount) {
</span><del>-            unsigned glyphStartOffset = complexTextRun.indexAt(g);
</del><ins>+            unsigned glyphStartOffset = complexTextRun.indexAt(glyphIndexIntoCurrentRun);
</ins><span class="cx">             unsigned glyphEndOffset;
</span><span class="cx">             if (complexTextRun.isMonotonic()) {
</span><span class="cx">                 if (ltr)
</span><del>-                    glyphEndOffset = std::max&lt;unsigned&gt;(glyphStartOffset, static_cast&lt;unsigned&gt;(g + 1 &lt; glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.indexEnd()));
</del><ins>+                    glyphEndOffset = std::max&lt;unsigned&gt;(glyphStartOffset, static_cast&lt;unsigned&gt;(glyphIndexIntoCurrentRun + 1 &lt; glyphCount ? complexTextRun.indexAt(glyphIndexIntoCurrentRun + 1) : complexTextRun.indexEnd()));
</ins><span class="cx">                 else
</span><del>-                    glyphEndOffset = std::max&lt;unsigned&gt;(glyphStartOffset, static_cast&lt;unsigned&gt;(g &gt; 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.indexEnd()));
</del><ins>+                    glyphEndOffset = std::max&lt;unsigned&gt;(glyphStartOffset, static_cast&lt;unsigned&gt;(glyphIndexIntoCurrentRun &gt; 0 ? complexTextRun.indexAt(glyphIndexIntoCurrentRun - 1) : complexTextRun.indexEnd()));
</ins><span class="cx">             } else
</span><del>-                glyphEndOffset = complexTextRun.endOffsetAt(g);
</del><ins>+                glyphEndOffset = complexTextRun.endOffsetAt(glyphIndexIntoCurrentRun);
</ins><span class="cx"> 
</span><del>-            CGSize adjustedBaseAdvance = m_adjustedBaseAdvances[k];
</del><ins>+            CGSize adjustedBaseAdvance = m_adjustedBaseAdvances[glyphIndexIntoComplexTextController];
</ins><span class="cx"> 
</span><span class="cx">             if (glyphStartOffset + complexTextRun.stringLocation() &gt;= m_currentCharacter)
</span><span class="cx">                 return;
</span><span class="cx"> 
</span><span class="cx">             if (glyphBuffer &amp;&amp; !m_characterInCurrentGlyph) {
</span><ins>+                auto currentGlyphOrigin = glyphOrigin(glyphIndexIntoComplexTextController);
</ins><span class="cx">                 GlyphBufferAdvance paintAdvance = adjustedBaseAdvance;
</span><del>-#if USE_LAYOUT_SPECIFIC_ADVANCES
-                if (k + 1 &lt; m_adjustedBaseAdvances.size()) {
-                    paintAdvance.setWidth(paintAdvance.width() + glyphOrigin(k + 1).x - glyphOrigin(k).x);
-                    paintAdvance.setHeight(paintAdvance.height() - glyphOrigin(k + 1).y + glyphOrigin(k).y);
</del><ins>+                if (!glyphIndexIntoCurrentRun) {
+                    // The first layout advance of every run includes the &quot;initial layout advance.&quot; However, here, we need
+                    // paint advances, so subtract it out before transforming the layout advance into a paint advance.
+                    paintAdvance.setWidth(paintAdvance.width() - (complexTextRun.initialAdvance().width - currentGlyphOrigin.x));
+                    paintAdvance.setHeight(paintAdvance.height() - (complexTextRun.initialAdvance().height - currentGlyphOrigin.y));
</ins><span class="cx">                 }
</span><del>-#endif
-                glyphBuffer-&gt;add(m_adjustedGlyphs[k], &amp;complexTextRun.font(), paintAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
</del><ins>+                paintAdvance.setWidth(paintAdvance.width() + glyphOrigin(glyphIndexIntoComplexTextController + 1).x - currentGlyphOrigin.x);
+                paintAdvance.setHeight(paintAdvance.height() + glyphOrigin(glyphIndexIntoComplexTextController + 1).y - currentGlyphOrigin.y);
+                if (glyphIndexIntoCurrentRun == glyphCount - 1 &amp;&amp; currentRunIndex + 1 &lt; runCount) {
+                    // Our paint advance points to the end of the run. However, the next run may have an
+                    // initial advance, and our paint advance needs to point to the location of the next
+                    // glyph. So, we need to add in the next run's initial advance.
+                    paintAdvance.setWidth(paintAdvance.width() - glyphOrigin(glyphIndexIntoComplexTextController + 1).x + m_complexTextRuns[currentRunIndex + 1]-&gt;initialAdvance().width);
+                    paintAdvance.setHeight(paintAdvance.height() - glyphOrigin(glyphIndexIntoComplexTextController + 1).y + m_complexTextRuns[currentRunIndex + 1]-&gt;initialAdvance().height);
+                }
+                paintAdvance.setHeight(-paintAdvance.height()); // Increasing y points down
+                glyphBuffer-&gt;add(m_adjustedGlyphs[glyphIndexIntoComplexTextController], &amp;complexTextRun.font(), paintAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
</span><span class="lines">@@ -636,14 +641,14 @@
</span><span class="cx">             m_glyphInCurrentRun++;
</span><span class="cx">             m_characterInCurrentGlyph = 0;
</span><span class="cx">             if (ltr) {
</span><del>-                g++;
-                k++;
</del><ins>+                glyphIndexIntoCurrentRun++;
+                glyphIndexIntoComplexTextController++;
</ins><span class="cx">             } else {
</span><del>-                g--;
-                k--;
</del><ins>+                glyphIndexIntoCurrentRun--;
+                glyphIndexIntoComplexTextController--;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><del>-        currentRunIndex = incrementCurrentRun(leftmostGlyph);
</del><ins>+        currentRunIndex = incrementCurrentRun(indexOfLeftmostGlyphInCurrentRun);
</ins><span class="cx">         m_glyphInCurrentRun = 0;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -690,16 +695,6 @@
</span><span class="cx">         unsigned glyphCount = complexTextRun.glyphCount();
</span><span class="cx">         const Font&amp; font = complexTextRun.font();
</span><span class="cx"> 
</span><del>-        // Represent the initial advance for a text run by adjusting the advance
-        // of the last glyph of the previous text run in the glyph buffer.
-        if (!complexTextRun.glyphOrigins() &amp;&amp; runIndex &amp;&amp; m_adjustedBaseAdvances.size()) {
-            CGSize previousAdvance = m_adjustedBaseAdvances.last();
-            previousAdvance.width += complexTextRun.initialAdvance().width;
-            previousAdvance.height -= complexTextRun.initialAdvance().height;
-            m_adjustedBaseAdvances[m_adjustedBaseAdvances.size() - 1] = previousAdvance;
-        }
-        widthSinceLastCommit += complexTextRun.initialAdvance().width;
-
</del><span class="cx">         if (!complexTextRun.isLTR())
</span><span class="cx">             m_isLTROnly = false;
</span><span class="cx"> 
</span><span class="lines">@@ -743,6 +738,15 @@
</span><span class="cx">                 glyph = font.spaceGlyph();
</span><span class="cx">             }
</span><span class="cx"> 
</span><ins>+            if (!i) {
+                advance.width += complexTextRun.initialAdvance().width;
+                advance.height += complexTextRun.initialAdvance().height;
+                if (auto* origins = complexTextRun.glyphOrigins()) {
+                    advance.width -= origins[0].x;
+                    advance.height -= origins[0].y;
+                }
+            }
+
</ins><span class="cx">             advance.width += font.syntheticBoldOffset();
</span><span class="cx"> 
</span><span class="cx">             if (hasExtraSpacing) {
</span><span class="lines">@@ -774,20 +778,17 @@
</span><span class="cx">                     if (m_expansion) {
</span><span class="cx">                         bool expandLeft, expandRight;
</span><span class="cx">                         std::tie(expandLeft, expandRight) = expansionLocation(ideograph, treatAsSpace, m_run.ltr(), afterExpansion, forbidLeadingExpansion, forbidTrailingExpansion, forceLeadingExpansion, forceTrailingExpansion);
</span><ins>+                        m_expansion -= m_expansionPerOpportunity;
+                        advance.width += m_expansionPerOpportunity;
</ins><span class="cx">                         if (expandLeft) {
</span><span class="cx">                             // Increase previous width
</span><del>-                            m_expansion -= m_expansionPerOpportunity;
-                            m_totalWidth += m_expansionPerOpportunity;
</del><span class="cx">                             if (m_adjustedBaseAdvances.isEmpty())
</span><del>-                                m_leadingExpansion = m_expansionPerOpportunity;
</del><ins>+                                complexTextRun.growInitialAdvanceHorizontally(m_expansionPerOpportunity);
</ins><span class="cx">                             else
</span><span class="cx">                                 m_adjustedBaseAdvances.last().width += m_expansionPerOpportunity;
</span><span class="cx">                         }
</span><del>-                        if (expandRight) {
-                            m_expansion -= m_expansionPerOpportunity;
-                            advance.width += m_expansionPerOpportunity;
</del><ins>+                        if (expandRight)
</ins><span class="cx">                             afterExpansion = true;
</span><del>-                        }
</del><span class="cx">                     } else
</span><span class="cx">                         afterExpansion = false;
</span><span class="cx"> 
</span><span class="lines">@@ -804,9 +805,7 @@
</span><span class="cx">             if (m_forTextEmphasis &amp;&amp; (!FontCascade::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) &amp; U_GC_M_MASK)))
</span><span class="cx">                 glyph = 0;
</span><span class="cx"> 
</span><del>-            advance.height *= -1;
</del><span class="cx">             m_adjustedBaseAdvances.append(advance);
</span><del>-#if USE_LAYOUT_SPECIFIC_ADVANCES
</del><span class="cx">             if (auto* origins = complexTextRun.glyphOrigins()) {
</span><span class="cx">                 ASSERT(m_glyphOrigins.size() &lt; m_adjustedBaseAdvances.size());
</span><span class="cx">                 m_glyphOrigins.grow(m_adjustedBaseAdvances.size());
</span><span class="lines">@@ -813,7 +812,6 @@
</span><span class="cx">                 m_glyphOrigins[m_glyphOrigins.size() - 1] = origins[i];
</span><span class="cx">                 ASSERT(m_glyphOrigins.size() == m_adjustedBaseAdvances.size());
</span><span class="cx">             }
</span><del>-#endif
</del><span class="cx">             m_adjustedGlyphs.append(glyph);
</span><span class="cx">             
</span><span class="cx">             FloatRect glyphBounds = font.boundsForGlyph(glyph);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsmacComplexTextControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -51,8 +51,7 @@
</span><span class="cx"> 
</span><span class="cx"> enum GlyphIterationStyle { IncludePartialGlyphs, ByWholeGlyphs };
</span><span class="cx"> 
</span><del>-// ComplexTextController is responsible for rendering and measuring glyphs for
-// complex scripts on macOS and iOS.
</del><ins>+// See https://trac.webkit.org/wiki/ComplexTextController for more information about ComplexTextController.
</ins><span class="cx"> class ComplexTextController {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><span class="lines">@@ -77,8 +76,6 @@
</span><span class="cx">     float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
</span><span class="cx">     float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
</span><span class="cx"> 
</span><del>-    float leadingExpansion() const { return m_leadingExpansion; }
-
</del><span class="cx">     class ComplexTextRun : public RefCounted&lt;ComplexTextRun&gt; {
</span><span class="cx">     public:
</span><span class="cx">         static Ref&lt;ComplexTextRun&gt; create(CTRunRef ctRun, const Font&amp; font, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange)
</span><span class="lines">@@ -108,15 +105,33 @@
</span><span class="cx">         const CGGlyph* glyphs() const { return m_glyphs; }
</span><span class="cx"> 
</span><span class="cx">         /*
</span><del>-         *                                              X (Paint glyph position)   X (Paint glyph position)   X (Paint glyph position)
-         *                                             7                          7                          7
-         *                                            /                          /                          /
-         *                                           / (Glyph origin)           / (Glyph origin)           / (Glyph origin)
-         *                                          /                          /                          /
-         *                                         /                          /                          /
-         *                X-----------------------X--------------------------X--------------------------X----&gt;...
-         * (text position ^)  (initial advance)          (base advance)             (base advance)
</del><ins>+         * This is the format of the information CoreText gives us about each run:
+         *
+         *                                        -----&gt;X (Paint glyph position)   X (Paint glyph position)   X (Paint glyph position)
+         *                                       /     7                          7                          7
+         *                                      /     /                          /                          /
+         *                   (Initial advance) /     / (Glyph origin)           / (Glyph origin)           / (Glyph origin)
+         *                  -------------------     /                          /                          /
+         *                 /                       /                          /                          /
+         *                X                       X--------------------------X--------------------------X--------------------------X
+         * (text position ^)                             (base advance)             (base advance)             (base advance)
+         *
+         *
+         *
+         *
+         *
+         * And here is the output we transform this into (for each run):
+         *
+         *                                        -----&gt;X-------------------------&gt;X-------------------------&gt;X
+         *                                       /            (Paint advance)            (Paint advance)       \
+         *                                      /                                                               \
+         *                   (Initial advance) /                                                                 \ (Paint advance)
+         *                  -------------------                                                                   ----------------
+         *                 /                                                                                                      \
+         *                X--------------------------------------------------X--------------------------X--------------------------X
+         * (text position ^)                (layout advance)                       (layout advance)           (layout advance)
</ins><span class="cx">          */
</span><ins>+        void growInitialAdvanceHorizontally(CGFloat delta) { m_initialAdvance.width += delta; }
</ins><span class="cx">         CGSize initialAdvance() const { return m_initialAdvance; }
</span><span class="cx">         const CGSize* baseAdvances() const { return m_baseAdvances; }
</span><span class="cx">         const CGPoint* glyphOrigins() const { return m_glyphOrigins.size() == glyphCount() ? m_glyphOrigins.data() : nullptr; }
</span><span class="lines">@@ -149,6 +164,7 @@
</span><span class="cx">         bool m_isMonotonic { true };
</span><span class="cx">     };
</span><span class="cx"> private:
</span><ins>+    void computeExpansionOpportunity();
</ins><span class="cx">     void finishConstruction();
</span><span class="cx">     
</span><span class="cx">     static unsigned stringBegin(const ComplexTextRun&amp; run) { return run.stringLocation() + run.indexBegin(); }
</span><span class="lines">@@ -206,7 +222,6 @@
</span><span class="cx">     unsigned m_characterInCurrentGlyph { 0 };
</span><span class="cx">     float m_expansion { 0 };
</span><span class="cx">     float m_expansionPerOpportunity { 0 };
</span><del>-    float m_leadingExpansion { 0 };
</del><span class="cx"> 
</span><span class="cx">     float m_minGlyphBoundingBoxX { std::numeric_limits&lt;float&gt;::max() };
</span><span class="cx">     float m_maxGlyphBoundingBoxX { std::numeric_limits&lt;float&gt;::min() };
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Tools/ChangeLog        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2017-01-30  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Correct spacing regression on inter-element complex path shaping on some fonts
+        https://bugs.webkit.org/show_bug.cgi?id=166013
+
+        Reviewed by Simon Fraser.
+
+        Unskip existing tests and make some new tests:
+        - Testing complex text with no origins
+        - Testing initial expansions
+        - Testing the sign of vertical advances
+
+        * TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp:
+        (TestWebKitAPI::TEST_F):
+
</ins><span class="cx"> 2017-01-30  Carlos Alberto Lopez Perez  &lt;clopez@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK][EFL] Avoid using a thin directory to create the built product on the archive-built-product step.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreComplexTextControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp (211381 => 211382)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp        2017-01-30 20:08:29 UTC (rev 211381)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ComplexTextController.cpp        2017-01-30 20:43:14 UTC (rev 211382)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-TEST_F(ComplexTextControllerTest, DISABLED_InitialAdvanceWithLeftRunInRTL)
</del><ins>+TEST_F(ComplexTextControllerTest, InitialAdvanceWithLeftRunInRTL)
</ins><span class="cx"> {
</span><span class="cx">     FontCascadeDescription description;
</span><span class="cx">     description.setOneFamily(&quot;Times&quot;);
</span><span class="lines">@@ -79,6 +79,7 @@
</span><span class="cx">         totalWidth += advances[i].width;
</span><span class="cx">     EXPECT_NEAR(controller.totalWidth(), spaceWidth + totalWidth, 0.0001);
</span><span class="cx">     GlyphBuffer glyphBuffer;
</span><ins>+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</ins><span class="cx">     controller.advance(0, &amp;glyphBuffer);
</span><span class="cx">     EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</span><span class="cx">     controller.advance(1, &amp;glyphBuffer);
</span><span class="lines">@@ -96,7 +97,7 @@
</span><span class="cx">     EXPECT_NEAR(glyphBuffer.advanceAt(5).width(), spaceWidth + initialAdvance.width, 0.0001);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST_F(ComplexTextControllerTest, DISABLED_InitialAdvanceInRTL)
</del><ins>+TEST_F(ComplexTextControllerTest, InitialAdvanceInRTL)
</ins><span class="cx"> {
</span><span class="cx">     FontCascadeDescription description;
</span><span class="cx">     description.setOneFamily(&quot;Times&quot;);
</span><span class="lines">@@ -127,6 +128,7 @@
</span><span class="cx">         totalWidth += advances[i].width;
</span><span class="cx">     EXPECT_NEAR(controller.totalWidth(), totalWidth, 0.0001);
</span><span class="cx">     GlyphBuffer glyphBuffer;
</span><ins>+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</ins><span class="cx">     controller.advance(0, &amp;glyphBuffer);
</span><span class="cx">     EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</span><span class="cx">     controller.advance(1, &amp;glyphBuffer);
</span><span class="lines">@@ -141,9 +143,10 @@
</span><span class="cx">     EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), advances[2].width, 0.0001);
</span><span class="cx">     EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), advances[1].width, 0.0001);
</span><span class="cx">     EXPECT_NEAR(glyphBuffer.advanceAt(4).width(), -initialAdvance.width, 0.0001);
</span><ins>+    EXPECT_NEAR(glyphBuffer.advanceAt(4).height(), initialAdvance.height, 0.0001);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST_F(ComplexTextControllerTest, DISABLED_InitialAdvanceWithLeftRunInLTR)
</del><ins>+TEST_F(ComplexTextControllerTest, InitialAdvanceWithLeftRunInLTR)
</ins><span class="cx"> {
</span><span class="cx">     FontCascadeDescription description;
</span><span class="cx">     description.setOneFamily(&quot;LucidaGrande&quot;);
</span><span class="lines">@@ -174,6 +177,7 @@
</span><span class="cx"> 
</span><span class="cx">     EXPECT_NEAR(controller.totalWidth(), spaceWidth + 76.347656 + initialAdvance.width, 0.0001);
</span><span class="cx">     GlyphBuffer glyphBuffer;
</span><ins>+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</ins><span class="cx">     controller.advance(0, &amp;glyphBuffer);
</span><span class="cx">     EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</span><span class="cx">     controller.advance(1, &amp;glyphBuffer);
</span><span class="lines">@@ -190,7 +194,7 @@
</span><span class="cx">     EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), 23.281250, 0.0001);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST_F(ComplexTextControllerTest, DISABLED_InitialAdvanceInLTR)
</del><ins>+TEST_F(ComplexTextControllerTest, InitialAdvanceInLTR)
</ins><span class="cx"> {
</span><span class="cx">     FontCascadeDescription description;
</span><span class="cx">     description.setOneFamily(&quot;LucidaGrande&quot;);
</span><span class="lines">@@ -218,6 +222,7 @@
</span><span class="cx"> 
</span><span class="cx">     EXPECT_NEAR(controller.totalWidth(), 76.347656 + initialAdvance.width, 0.0001);
</span><span class="cx">     GlyphBuffer glyphBuffer;
</span><ins>+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</ins><span class="cx">     controller.advance(0, &amp;glyphBuffer);
</span><span class="cx">     EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
</span><span class="cx">     controller.advance(1, &amp;glyphBuffer);
</span><span class="lines">@@ -231,4 +236,124 @@
</span><span class="cx">     EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 23.281250, 0.0001);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST_F(ComplexTextControllerTest, InitialAdvanceInRTLNoOrigins)
+{
+    FontCascadeDescription description;
+    description.setOneFamily(&quot;Times&quot;);
+    description.setComputedSize(48);
+    FontCascade font(description);
+    font.update();
+
+    CGSize initialAdvance = CGSizeMake(4.33996383363472, 12.368896925859);
+
+    UChar characters[] = { 0x633, 0x20, 0x627, 0x650 };
+    size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+    TextRun textRun(StringView(characters, charactersLength));
+    auto run1 = ComplexTextController::ComplexTextRun::createForTesting({ CGSizeMake(-4.33996383363472, -12.368896925859), CGSizeMake(14.0397830018083, 0) }, { }, { 884, 240 }, { 3, 2 }, initialAdvance, font.primaryFont(), characters, 0, charactersLength, CFRangeMake(2, 2), false);
+    auto run2 = ComplexTextController::ComplexTextRun::createForTesting({ CGSizeMake(12.0, 0) }, { }, { 3 }, { 1 }, CGSizeZero, font.primaryFont(), characters, 0, charactersLength, CFRangeMake(1, 1), false);
+    auto run3 = ComplexTextController::ComplexTextRun::createForTesting({ CGSizeMake(43.8119349005425, 0) }, { }, { 276 }, { 0 }, CGSizeZero, font.primaryFont(), characters, 0, charactersLength, CFRangeMake(0, 1), false);
+    Vector&lt;Ref&lt;ComplexTextController::ComplexTextRun&gt;&gt; runs;
+    runs.append(WTFMove(run1));
+    runs.append(WTFMove(run2));
+    runs.append(WTFMove(run3));
+    ComplexTextController controller(font, textRun, runs);
+
+    CGFloat totalWidth = 14.0397830018083 + 12.0 + 43.8119349005425;
+    EXPECT_NEAR(controller.totalWidth(), totalWidth, 0.0001);
+    GlyphBuffer glyphBuffer;
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(0, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(1, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 43.8119349005425, 0.0001);
+    controller.advance(2, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 43.8119349005425 + 12.0, 0.0001);
+    controller.advance(3, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+    controller.advance(4, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+    EXPECT_NEAR(glyphBuffer.initialAdvance().width(), initialAdvance.width, 0.0001);
+    EXPECT_NEAR(glyphBuffer.initialAdvance().height(), initialAdvance.height, 0.0001);
+    EXPECT_EQ(glyphBuffer.size(), 4U);
+    EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 43.8119349005425, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 12.0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), 14.0397830018083, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), -4.33996383363472, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(3).height(), 12.368896925859, 0.0001);
</ins><span class="cx"> }
</span><ins>+
+TEST_F(ComplexTextControllerTest, LeadingExpansion)
+{
+    FontCascadeDescription description;
+    description.setOneFamily(&quot;Times&quot;);
+    description.setComputedSize(48);
+    FontCascade font(description);
+    font.update();
+
+    UChar characters[] = { 'a' };
+    size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+    TextRun textRun(StringView(characters, charactersLength), 0, 100, ForceLeadingExpansion);
+    auto run = ComplexTextController::ComplexTextRun::createForTesting({ CGSizeMake(24, 0) }, { }, { 16 }, { 0 }, CGSizeZero, font.primaryFont(), characters, 0, charactersLength, CFRangeMake(0, 1), true);
+    Vector&lt;Ref&lt;ComplexTextController::ComplexTextRun&gt;&gt; runs;
+    runs.append(WTFMove(run));
+    ComplexTextController controller(font, textRun, runs);
+
+    CGFloat totalWidth = 100 + 24;
+    EXPECT_NEAR(controller.totalWidth(), totalWidth, 0.0001);
+    GlyphBuffer glyphBuffer;
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(0, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(1, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), totalWidth, 0.0001);
+    EXPECT_NEAR(glyphBuffer.initialAdvance().width(), 100, 0.0001);
+    EXPECT_NEAR(glyphBuffer.initialAdvance().height(), 0, 0.0001);
+    EXPECT_EQ(glyphBuffer.size(), 1U);
+    EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 24, 0.0001);
+}
+
+TEST_F(ComplexTextControllerTest, VerticalAdvances)
+{
+    FontCascadeDescription description;
+    description.setOneFamily(&quot;Times&quot;);
+    description.setComputedSize(48);
+    FontCascade font(description);
+    font.update();
+
+    UChar characters[] = { 'a', 'b', 'c', 'd' };
+    size_t charactersLength = WTF_ARRAY_LENGTH(characters);
+    TextRun textRun(StringView(characters, charactersLength));
+    auto run1 = ComplexTextController::ComplexTextRun::createForTesting({ CGSizeMake(0, 1), CGSizeMake(0, 2) }, { CGPointMake(0, 4), CGPointMake(0, 8) }, { 16, 17 }, { 0, 1 }, CGSizeMake(0, 16), font.primaryFont(), characters, 0, charactersLength, CFRangeMake(0, 2), true);
+    auto run2 = ComplexTextController::ComplexTextRun::createForTesting({ CGSizeMake(0, 32), CGSizeMake(0, 64) }, { CGPointMake(0, 128), CGPointMake(0, 256) }, { 18, 19 }, { 2, 3 }, CGSizeMake(0, 512), font.primaryFont(), characters, 0, charactersLength, CFRangeMake(2, 2), true);
+    Vector&lt;Ref&lt;ComplexTextController::ComplexTextRun&gt;&gt; runs;
+    runs.append(WTFMove(run1));
+    runs.append(WTFMove(run2));
+    ComplexTextController controller(font, textRun, runs);
+
+    EXPECT_NEAR(controller.totalWidth(), 0, 0.0001);
+    GlyphBuffer glyphBuffer;
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(0, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(1, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(2, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(3, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    controller.advance(4, &amp;glyphBuffer);
+    EXPECT_NEAR(controller.runWidthSoFar(), 0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.initialAdvance().width(), 0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.initialAdvance().height(), 16, 0.0001);
+    EXPECT_EQ(glyphBuffer.size(), 4U);
+    EXPECT_NEAR(glyphBuffer.advanceAt(0).width(), 0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(0).height(), 4 - 1 -8, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(1).width(), 0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(1).height(), 8 - 2 - 512, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(2).width(), 0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(2).height(), 128 - 32 - 256, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(3).width(), 0, 0.0001);
+    EXPECT_NEAR(glyphBuffer.advanceAt(3).height(), 256 - 64, 0.0001);
+}
+
+}
</ins></span></pre>
</div>
</div>

</body>
</html>