Title: [211776] trunk/Source/WebCore
Revision
211776
Author
mmaxfi...@apple.com
Date
2017-02-07 00:14:06 -0800 (Tue, 07 Feb 2017)

Log Message

Move platform-independent parts of ComplexTextController out of mac/ subfolder
https://bugs.webkit.org/show_bug.cgi?id=167922

Reviewed by Jon Lee.

Just a mechanical git mv, and updating the Xcode projects.

No new tests because there is no behavior change.

* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/ComplexTextController.cpp: Renamed from Source/WebCore/platform/graphics/mac/ComplexTextController.cpp.
* platform/graphics/ComplexTextController.h: Renamed from Source/WebCore/platform/graphics/mac/ComplexTextController.h.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (211775 => 211776)


--- trunk/Source/WebCore/ChangeLog	2017-02-07 06:45:43 UTC (rev 211775)
+++ trunk/Source/WebCore/ChangeLog	2017-02-07 08:14:06 UTC (rev 211776)
@@ -1,3 +1,18 @@
+2017-02-07  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+        Move platform-independent parts of ComplexTextController out of mac/ subfolder
+        https://bugs.webkit.org/show_bug.cgi?id=167922
+
+        Reviewed by Jon Lee.
+
+        Just a mechanical git mv, and updating the Xcode projects.
+
+        No new tests because there is no behavior change.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/ComplexTextController.cpp: Renamed from Source/WebCore/platform/graphics/mac/ComplexTextController.cpp.
+        * platform/graphics/ComplexTextController.h: Renamed from Source/WebCore/platform/graphics/mac/ComplexTextController.h.
+
 2017-02-06  Carlos Garcia Campos  <cgar...@igalia.com>
 
         Overlay scrolling with iframe-s broken

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (211775 => 211776)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-02-07 06:45:43 UTC (rev 211775)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-02-07 08:14:06 UTC (rev 211776)
@@ -1464,8 +1464,6 @@
 		37ACCF690DA414E70089E602 /* FontDescription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37ACCE620DA2AA960089E602 /* FontDescription.cpp */; };
 		37B327D31D17096A005737FA /* PIPSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 37B327D21D17096A005737FA /* PIPSPI.h */; };
 		37BAAE581980D1DD005DFE71 /* ProtectionSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 37BAAE571980D1DD005DFE71 /* ProtectionSpace.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		37C236101097EE7700EF9F72 /* ComplexTextController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37C2360E1097EE7700EF9F72 /* ComplexTextController.cpp */; };
-		37C236111097EE7700EF9F72 /* ComplexTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = 37C2360F1097EE7700EF9F72 /* ComplexTextController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		37C238221098C84200EF9F72 /* ComplexTextControllerCoreText.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C238201098C84200EF9F72 /* ComplexTextControllerCoreText.mm */; };
 		37D456FD1A9A50D8003330A1 /* LocalizableStrings.pm in Copy Scripts */ = {isa = PBXBuildFile; fileRef = 37D456FB1A9A50B6003330A1 /* LocalizableStrings.pm */; };
 		37DDCD9413844FD50008B793 /* MIMEHeader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37DDCD9213844FD50008B793 /* MIMEHeader.cpp */; };
@@ -5682,6 +5680,8 @@
 		C28083401C6DC275001451B6 /* JSFontFace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C280833D1C6DC22C001451B6 /* JSFontFace.cpp */; };
 		C28083421C6DC96A001451B6 /* JSFontFaceCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28083411C6DC96A001451B6 /* JSFontFaceCustom.cpp */; };
 		C2E1F43F1D6254E10094625C /* BreakLines.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA4816097D93020094C9E4 /* BreakLines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		C2F4E78A1E45BEA1006D7105 /* ComplexTextController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F4E7881E45AEDF006D7105 /* ComplexTextController.cpp */; };
+		C2F4E78C1E45C3EF006D7105 /* ComplexTextController.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F4E7891E45AEDF006D7105 /* ComplexTextController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		C330A22313EC196B0000B45B /* ColorChooser.h in Headers */ = {isa = PBXBuildFile; fileRef = C330A22113EC196B0000B45B /* ColorChooser.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		C33EE5C414FB49610002095A /* BaseClickableWithKeyInputType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C33EE5C214FB49610002095A /* BaseClickableWithKeyInputType.cpp */; };
 		C33EE5C514FB49610002095A /* BaseClickableWithKeyInputType.h in Headers */ = {isa = PBXBuildFile; fileRef = C33EE5C314FB49610002095A /* BaseClickableWithKeyInputType.h */; };
@@ -8707,8 +8707,6 @@
 		37ACCE620DA2AA960089E602 /* FontDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontDescription.cpp; sourceTree = "<group>"; };
 		37B327D21D17096A005737FA /* PIPSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PIPSPI.h; sourceTree = "<group>"; };
 		37BAAE571980D1DD005DFE71 /* ProtectionSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProtectionSpace.h; sourceTree = "<group>"; };
-		37C2360E1097EE7700EF9F72 /* ComplexTextController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexTextController.cpp; sourceTree = "<group>"; };
-		37C2360F1097EE7700EF9F72 /* ComplexTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexTextController.h; sourceTree = "<group>"; };
 		37C238201098C84200EF9F72 /* ComplexTextControllerCoreText.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ComplexTextControllerCoreText.mm; sourceTree = "<group>"; };
 		37D456FB1A9A50B6003330A1 /* LocalizableStrings.pm */ = {isa = PBXFileReference; lastKnownFileType = text.script.perl; path = LocalizableStrings.pm; sourceTree = "<group>"; };
 		37DDCD9213844FD50008B793 /* MIMEHeader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MIMEHeader.cpp; sourceTree = "<group>"; };
@@ -13714,6 +13712,8 @@
 		C280833D1C6DC22C001451B6 /* JSFontFace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFontFace.cpp; sourceTree = "<group>"; };
 		C280833E1C6DC22C001451B6 /* JSFontFace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFontFace.h; sourceTree = "<group>"; };
 		C28083411C6DC96A001451B6 /* JSFontFaceCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFontFaceCustom.cpp; sourceTree = "<group>"; };
+		C2F4E7881E45AEDF006D7105 /* ComplexTextController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexTextController.cpp; sourceTree = "<group>"; };
+		C2F4E7891E45AEDF006D7105 /* ComplexTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexTextController.h; sourceTree = "<group>"; };
 		C330A22113EC196B0000B45B /* ColorChooser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColorChooser.h; sourceTree = "<group>"; };
 		C33EE5C214FB49610002095A /* BaseClickableWithKeyInputType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BaseClickableWithKeyInputType.cpp; sourceTree = "<group>"; };
 		C33EE5C314FB49610002095A /* BaseClickableWithKeyInputType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseClickableWithKeyInputType.h; sourceTree = "<group>"; };
@@ -21887,8 +21887,6 @@
 			children = (
 				EDE3A4FF0C7A430600956A37 /* ColorMac.h */,
 				B275354A0B053814002CE64F /* ColorMac.mm */,
-				37C2360E1097EE7700EF9F72 /* ComplexTextController.cpp */,
-				37C2360F1097EE7700EF9F72 /* ComplexTextController.h */,
 				37C238201098C84200EF9F72 /* ComplexTextControllerCoreText.mm */,
 				49AF2D6B14435D210016A784 /* DisplayRefreshMonitorMac.cpp */,
 				2DE70022192FE82A00B0975C /* DisplayRefreshMonitorMac.h */,
@@ -21923,6 +21921,8 @@
 		B2A015910AF6CD53006BCE0E /* graphics */ = {
 			isa = PBXGroup;
 			children = (
+				C2F4E7881E45AEDF006D7105 /* ComplexTextController.cpp */,
+				C2F4E7891E45AEDF006D7105 /* ComplexTextController.h */,
 				076F0D0812B8192700C26AA4 /* avfoundation */,
 				499B3EC0128CCC1800E726C2 /* ca */,
 				B27535290B053814002CE64F /* cg */,
@@ -25172,6 +25172,7 @@
 				FD31603E12B0267600C1A359 /* AnalyserNode.h in Headers */,
 				31A795C71888BCB200382F90 /* ANGLEInstancedArrays.h in Headers */,
 				490707E71219C04300D90E51 /* ANGLEWebKitBridge.h in Headers */,
+				C2F4E78C1E45C3EF006D7105 /* ComplexTextController.h in Headers */,
 				49E912AB0EFAC906009D0CAF /* Animation.h in Headers */,
 				316FE1120E6E1DA700BF6088 /* AnimationBase.h in Headers */,
 				319848011A1D817B00A13318 /* AnimationEvent.h in Headers */,
@@ -25434,7 +25435,6 @@
 				E1FE137518402A6700892F13 /* CommonCryptoUtilities.h in Headers */,
 				0F60F32B1DFBB10700416D6C /* CommonVM.h in Headers */,
 				7C93F34A1AA6BA5E00A98BAB /* CompiledContentExtension.h in Headers */,
-				37C236111097EE7700EF9F72 /* ComplexTextController.h in Headers */,
 				E4BA50901BCFBD9500E34EF7 /* ComposedTreeAncestorIterator.h in Headers */,
 				E44FA1851BCA6B5A0091B6EF /* ComposedTreeIterator.h in Headers */,
 				316FE1160E6E1DA700BF6088 /* CompositeAnimation.h in Headers */,
@@ -29338,7 +29338,6 @@
 				E1FE137418402A6700892F13 /* CommonCryptoUtilities.cpp in Sources */,
 				0F60F32C1DFBB10B00416D6C /* CommonVM.cpp in Sources */,
 				7C93F3491AA6BA5E00A98BAB /* CompiledContentExtension.cpp in Sources */,
-				37C236101097EE7700EF9F72 /* ComplexTextController.cpp in Sources */,
 				37C238221098C84200EF9F72 /* ComplexTextControllerCoreText.mm in Sources */,
 				E44FA1871BCA91560091B6EF /* ComposedTreeIterator.cpp in Sources */,
 				316FE1150E6E1DA700BF6088 /* CompositeAnimation.cpp in Sources */,
@@ -31308,6 +31307,7 @@
 				D06C0D900CFD11460065F43F /* RemoveFormatCommand.cpp in Sources */,
 				93309E04099E64920056E581 /* RemoveNodeCommand.cpp in Sources */,
 				93309E06099E64920056E581 /* RemoveNodePreservingChildrenCommand.cpp in Sources */,
+				C2F4E78A1E45BEA1006D7105 /* ComplexTextController.cpp in Sources */,
 				7CD494CC1A86EB1D000A87EC /* RenderAttachment.cpp in Sources */,
 				BCEA485F097D93020094C9E4 /* RenderBlock.cpp in Sources */,
 				BC10D76717D8EE6E005E2626 /* RenderBlockFlow.cpp in Sources */,

Copied: trunk/Source/WebCore/platform/graphics/ComplexTextController.cpp (from rev 211775, trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp) (0 => 211776)


--- trunk/Source/WebCore/platform/graphics/ComplexTextController.cpp	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/ComplexTextController.cpp	2017-02-07 08:14:06 UTC (rev 211776)
@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ComplexTextController.h"
+
+#include "CharacterProperties.h"
+#include "FloatSize.h"
+#include "FontCascade.h"
+#include "RenderBlock.h"
+#include "RenderText.h"
+#include "TextRun.h"
+#include <unicode/ubrk.h>
+#include <wtf/Optional.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/TextBreakIterator.h>
+#include <wtf/unicode/CharacterNames.h>
+
+#if PLATFORM(IOS)
+#include <CoreText/CoreText.h>
+#endif
+
+#if PLATFORM(MAC)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace WebCore {
+
+class TextLayout {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static bool isNeeded(RenderText& text, const FontCascade& font)
+    {
+        TextRun run = RenderBlock::constructTextRun(text, text.style());
+        return font.codePath(run) == FontCascade::Complex;
+    }
+
+    TextLayout(RenderText& text, const FontCascade& font, float xPos)
+        : m_font(font)
+        , m_run(constructTextRun(text, xPos))
+        , m_controller(std::make_unique<ComplexTextController>(m_font, m_run, true))
+    {
+    }
+
+    float width(unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts)
+    {
+        m_controller->advance(from, 0, ByWholeGlyphs, fallbackFonts);
+        float beforeWidth = m_controller->runWidthSoFar();
+        if (m_font.wordSpacing() && from && FontCascade::treatAsSpace(m_run[from]))
+            beforeWidth += m_font.wordSpacing();
+        m_controller->advance(from + len, 0, ByWholeGlyphs, fallbackFonts);
+        float afterWidth = m_controller->runWidthSoFar();
+        return afterWidth - beforeWidth;
+    }
+
+private:
+    static TextRun constructTextRun(RenderText& text, float xPos)
+    {
+        TextRun run = RenderBlock::constructTextRun(text, text.style());
+        run.setCharactersLength(text.textLength());
+        ASSERT(run.charactersLength() >= run.length());
+        run.setXPos(xPos);
+        return run;
+    }
+
+    // ComplexTextController has only references to its FontCascade and TextRun so they must be kept alive here.
+    FontCascade m_font;
+    TextRun m_run;
+    std::unique_ptr<ComplexTextController> m_controller;
+};
+
+void TextLayoutDeleter::operator()(TextLayout* layout) const
+{
+    delete layout;
+}
+
+std::unique_ptr<TextLayout, TextLayoutDeleter> FontCascade::createLayout(RenderText& text, float xPos, bool collapseWhiteSpace) const
+{
+    if (!collapseWhiteSpace || !TextLayout::isNeeded(text, *this))
+        return nullptr;
+    return std::unique_ptr<TextLayout, TextLayoutDeleter>(new TextLayout(text, *this, xPos));
+}
+
+float FontCascade::width(TextLayout& layout, unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts)
+{
+    return layout.width(from, len, fallbackFonts);
+}
+
+void ComplexTextController::computeExpansionOpportunity()
+{
+    if (!m_expansion)
+        m_expansionPerOpportunity = 0;
+    else {
+        unsigned expansionOpportunityCount = FontCascade::expansionOpportunityCount(m_run.text(), m_run.ltr() ? LTR : RTL, m_run.expansionBehavior()).first;
+
+        if (!expansionOpportunityCount)
+            m_expansionPerOpportunity = 0;
+        else
+            m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
+    }
+}
+
+ComplexTextController::ComplexTextController(const FontCascade& font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const Font*>* 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();
+
+    collectComplexTextRuns();
+
+    finishConstruction();
+}
+
+ComplexTextController::ComplexTextController(const FontCascade& font, const TextRun& run, Vector<Ref<ComplexTextRun>>& runs)
+    : m_font(font)
+    , m_run(run)
+    , m_end(run.length())
+    , m_expansion(run.expansion())
+{
+    computeExpansionOpportunity();
+
+    for (auto& run : runs)
+        m_complexTextRuns.append(run.ptr());
+
+    finishConstruction();
+}
+
+void ComplexTextController::finishConstruction()
+{
+    adjustGlyphsAndAdvances();
+
+    if (!m_isLTROnly) {
+        m_runIndices.reserveInitialCapacity(m_complexTextRuns.size());
+
+        m_glyphCountFromStartToIndex.reserveInitialCapacity(m_complexTextRuns.size());
+        unsigned glyphCountSoFar = 0;
+        for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
+            m_glyphCountFromStartToIndex.uncheckedAppend(glyphCountSoFar);
+            glyphCountSoFar += m_complexTextRuns[i]->glyphCount();
+        }
+    }
+}
+
+unsigned ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
+{
+    if (h >= m_totalWidth)
+        return m_run.ltr() ? m_end : 0;
+
+    if (h < 0)
+        return m_run.ltr() ? 0 : m_end;
+
+    float x = h;
+
+    size_t runCount = m_complexTextRuns.size();
+    unsigned offsetIntoAdjustedGlyphs = 0;
+
+    for (size_t r = 0; r < runCount; ++r) {
+        const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
+        for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
+            unsigned index = offsetIntoAdjustedGlyphs + j;
+            float adjustedAdvance = m_adjustedBaseAdvances[index].width();
+            if (x < adjustedAdvance) {
+                unsigned hitGlyphStart = complexTextRun.indexAt(j);
+                unsigned hitGlyphEnd;
+                if (m_run.ltr())
+                    hitGlyphEnd = std::max(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : complexTextRun.indexEnd());
+                else
+                    hitGlyphEnd = std::max(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.indexEnd());
+
+                // FIXME: Instead of dividing the glyph's advance equally between the characters, this
+                // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
+                unsigned hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
+                unsigned stringLength = complexTextRun.stringLength();
+                UBreakIterator* cursorPositionIterator = cursorMovementIterator(StringView(complexTextRun.characters(), stringLength));
+                unsigned clusterStart;
+                if (ubrk_isBoundary(cursorPositionIterator, hitIndex))
+                    clusterStart = hitIndex;
+                else {
+                    int preceeding = ubrk_preceding(cursorPositionIterator, hitIndex);
+                    clusterStart = preceeding == UBRK_DONE ? 0 : preceeding;
+                }
+
+                if (!includePartialGlyphs)
+                    return complexTextRun.stringLocation() + clusterStart;
+
+                int following = ubrk_following(cursorPositionIterator, hitIndex);
+                unsigned clusterEnd = following == UBRK_DONE ? stringLength : following;
+
+                float clusterWidth;
+                // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
+                // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
+                // reordering and no font fallback should occur within a CTLine.
+                if (clusterEnd - clusterStart > 1) {
+                    clusterWidth = adjustedAdvance;
+                    if (j) {
+                        unsigned firstGlyphBeforeCluster = j - 1;
+                        while (complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
+                            float width = m_adjustedBaseAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width();
+                            clusterWidth += width;
+                            x += width;
+                            if (!firstGlyphBeforeCluster)
+                                break;
+                            firstGlyphBeforeCluster--;
+                        }
+                    }
+                    unsigned firstGlyphAfterCluster = j + 1;
+                    while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
+                        clusterWidth += m_adjustedBaseAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width();
+                        firstGlyphAfterCluster++;
+                    }
+                } else {
+                    clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
+                    x -=  clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
+                }
+                if (x <= clusterWidth / 2)
+                    return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
+                return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
+            }
+            x -= adjustedAdvance;
+        }
+        offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
+    }
+
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+// FIXME: We should consider reimplementing this function using ICU to advance by grapheme.
+// The current implementation only considers explicitly emoji sequences and emoji variations.
+static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UChar* end, UChar32& baseCharacter, unsigned& markCount)
+{
+    ASSERT(iterator < end);
+
+    markCount = 0;
+
+    unsigned i = 0;
+    unsigned remainingCharacters = end - iterator;
+    U16_NEXT(iterator, i, remainingCharacters, baseCharacter);
+    iterator = iterator + i;
+    if (U_IS_SURROGATE(baseCharacter))
+        return false;
+
+    // Consume marks.
+    bool sawEmojiGroupCandidate = isEmojiGroupCandidate(baseCharacter);
+    bool sawJoiner = false;
+    while (iterator < end) {
+        UChar32 nextCharacter;
+        unsigned markLength = 0;
+        bool shouldContinue = false;
+        ASSERT(end >= iterator);
+        U16_NEXT(iterator, markLength, static_cast<unsigned>(end - iterator), nextCharacter);
+
+        if (isVariationSelector(nextCharacter) || isEmojiFitzpatrickModifier(nextCharacter))
+            shouldContinue = true;
+
+        if (sawJoiner && isEmojiGroupCandidate(nextCharacter))
+            shouldContinue = true;
+
+        sawJoiner = false;
+        if (sawEmojiGroupCandidate && nextCharacter == zeroWidthJoiner) {
+            sawJoiner = true;
+            shouldContinue = true;
+        }
+        
+        if (!shouldContinue && !(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
+            break;
+
+        markCount += markLength;
+        iterator += markLength;
+    }
+
+    return true;
+}
+
+// FIXME: Capitalization is language-dependent and context-dependent and should operate on grapheme clusters instead of codepoints.
+static inline std::optional<UChar32> capitalized(UChar32 baseCharacter)
+{
+    if (U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK)
+        return std::nullopt;
+
+    UChar32 uppercaseCharacter = u_toupper(baseCharacter);
+    ASSERT(uppercaseCharacter == baseCharacter || (U_IS_BMP(baseCharacter) == U_IS_BMP(uppercaseCharacter)));
+    if (uppercaseCharacter != baseCharacter)
+        return uppercaseCharacter;
+    return std::nullopt;
+}
+
+static bool shouldSynthesize(bool dontSynthesizeSmallCaps, const Font* nextFont, UChar32 baseCharacter, std::optional<UChar32> capitalizedBase, FontVariantCaps fontVariantCaps, bool engageAllSmallCapsProcessing)
+{
+    if (dontSynthesizeSmallCaps)
+        return false;
+    if (!nextFont || nextFont == Font::systemFallback())
+        return false;
+    if (engageAllSmallCapsProcessing && isASCIISpace(baseCharacter))
+        return false;
+    if (!engageAllSmallCapsProcessing && !capitalizedBase)
+        return false;
+    return !nextFont->variantCapsSupportsCharacterForSynthesis(fontVariantCaps, baseCharacter);
+}
+
+void ComplexTextController::collectComplexTextRuns()
+{
+    if (!m_end)
+        return;
+
+    // We break up glyph run generation for the string by Font.
+    const UChar* cp;
+
+    if (m_run.is8Bit()) {
+        String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
+        m_stringsFor8BitRuns.append(WTFMove(stringFor8BitRun));
+        cp = m_stringsFor8BitRuns.last().characters16();
+    } else
+        cp = m_run.characters16();
+
+    auto fontVariantCaps = m_font.fontDescription().variantCaps();
+    bool dontSynthesizeSmallCaps = !static_cast<bool>(m_font.fontDescription().fontSynthesis() & FontSynthesisSmallCaps);
+    bool engageAllSmallCapsProcessing = fontVariantCaps == FontVariantCaps::AllSmall || fontVariantCaps == FontVariantCaps::AllPetite;
+    bool engageSmallCapsProcessing = engageAllSmallCapsProcessing || fontVariantCaps == FontVariantCaps::Small || fontVariantCaps == FontVariantCaps::Petite;
+
+    if (engageAllSmallCapsProcessing || engageSmallCapsProcessing)
+        m_smallCapsBuffer.resize(m_end);
+
+    unsigned indexOfFontTransition = 0;
+    const UChar* curr = cp;
+    const UChar* end = cp + m_end;
+
+    const Font* font;
+    const Font* nextFont;
+    const Font* synthesizedFont = nullptr;
+    const Font* smallSynthesizedFont = nullptr;
+
+    unsigned markCount;
+    UChar32 baseCharacter;
+    if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
+        return;
+
+    nextFont = m_font.fontForCombiningCharacterSequence(cp, curr - cp);
+
+    bool isSmallCaps = false;
+    bool nextIsSmallCaps = false;
+
+    auto capitalizedBase = capitalized(baseCharacter);
+    if (shouldSynthesize(dontSynthesizeSmallCaps, nextFont, baseCharacter, capitalizedBase, fontVariantCaps, engageAllSmallCapsProcessing)) {
+        synthesizedFont = &nextFont->noSynthesizableFeaturesFont();
+        smallSynthesizedFont = synthesizedFont->smallCapsFont(m_font.fontDescription());
+        UChar32 characterToWrite = capitalizedBase ? capitalizedBase.value() : cp[0];
+        unsigned characterIndex = 0;
+        U16_APPEND_UNSAFE(m_smallCapsBuffer, characterIndex, characterToWrite);
+        for (unsigned i = characterIndex; cp + i < curr; ++i)
+            m_smallCapsBuffer[i] = cp[i];
+        nextIsSmallCaps = true;
+    }
+
+    while (curr < end) {
+        font = nextFont;
+        isSmallCaps = nextIsSmallCaps;
+        unsigned index = curr - cp;
+
+        if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
+            return;
+
+        if (synthesizedFont) {
+            if (auto capitalizedBase = capitalized(baseCharacter)) {
+                unsigned characterIndex = index;
+                U16_APPEND_UNSAFE(m_smallCapsBuffer, characterIndex, capitalizedBase.value());
+                for (unsigned i = 0; i < markCount; ++i)
+                    m_smallCapsBuffer[i + characterIndex] = cp[i + characterIndex];
+                nextIsSmallCaps = true;
+            } else {
+                if (engageAllSmallCapsProcessing) {
+                    for (unsigned i = 0; i < curr - cp - index; ++i)
+                        m_smallCapsBuffer[index + i] = cp[index + i];
+                }
+                nextIsSmallCaps = engageAllSmallCapsProcessing;
+            }
+        }
+
+        if (baseCharacter == zeroWidthJoiner)
+            nextFont = font;
+        else
+            nextFont = m_font.fontForCombiningCharacterSequence(cp + index, curr - cp - index);
+
+        capitalizedBase = capitalized(baseCharacter);
+        if (!synthesizedFont && shouldSynthesize(dontSynthesizeSmallCaps, nextFont, baseCharacter, capitalizedBase, fontVariantCaps, engageAllSmallCapsProcessing)) {
+            // Rather than synthesize each character individually, we should synthesize the entire "run" if any character requires synthesis.
+            synthesizedFont = &nextFont->noSynthesizableFeaturesFont();
+            smallSynthesizedFont = synthesizedFont->smallCapsFont(m_font.fontDescription());
+            nextIsSmallCaps = true;
+            curr = cp + indexOfFontTransition;
+            continue;
+        }
+
+        if (nextFont != font || nextIsSmallCaps != isSmallCaps) {
+            unsigned itemLength = index - indexOfFontTransition;
+            if (itemLength) {
+                unsigned itemStart = indexOfFontTransition;
+                if (synthesizedFont) {
+                    if (isSmallCaps)
+                        collectComplexTextRunsForCharacters(m_smallCapsBuffer.data() + itemStart, itemLength, itemStart, smallSynthesizedFont);
+                    else
+                        collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, synthesizedFont);
+                } else
+                    collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, font);
+                if (nextFont != font) {
+                    synthesizedFont = nullptr;
+                    smallSynthesizedFont = nullptr;
+                    nextIsSmallCaps = false;
+                }
+            }
+            indexOfFontTransition = index;
+        }
+    }
+
+    ASSERT(m_end >= indexOfFontTransition);
+    unsigned itemLength = m_end - indexOfFontTransition;
+    if (itemLength) {
+        unsigned itemStart = indexOfFontTransition;
+        if (synthesizedFont) {
+            if (nextIsSmallCaps)
+                collectComplexTextRunsForCharacters(m_smallCapsBuffer.data() + itemStart, itemLength, itemStart, smallSynthesizedFont);
+            else
+                collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, synthesizedFont);
+        } else
+            collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, nextFont);
+    }
+
+    if (!m_run.ltr())
+        m_complexTextRuns.reverse();
+}
+
+unsigned ComplexTextController::ComplexTextRun::indexAt(unsigned i) const
+{
+    ASSERT(i < m_glyphCount);
+
+    return m_coreTextIndices[i];
+}
+
+void ComplexTextController::ComplexTextRun::setIsNonMonotonic()
+{
+    ASSERT(m_isMonotonic);
+    m_isMonotonic = false;
+
+    Vector<bool, 64> mappedIndices(m_stringLength, false);
+    for (unsigned i = 0; i < m_glyphCount; ++i) {
+        ASSERT(indexAt(i) < m_stringLength);
+        mappedIndices[indexAt(i)] = true;
+    }
+
+    m_glyphEndOffsets.grow(m_glyphCount);
+    for (unsigned i = 0; i < m_glyphCount; ++i) {
+        unsigned nextMappedIndex = m_indexEnd;
+        for (unsigned j = indexAt(i) + 1; j < m_stringLength; ++j) {
+            if (mappedIndices[j]) {
+                nextMappedIndex = j;
+                break;
+            }
+        }
+        m_glyphEndOffsets[i] = nextMappedIndex;
+    }
+}
+
+unsigned ComplexTextController::indexOfCurrentRun(unsigned& leftmostGlyph)
+{
+    leftmostGlyph = 0;
+    
+    size_t runCount = m_complexTextRuns.size();
+    if (m_currentRun >= runCount)
+        return runCount;
+
+    if (m_isLTROnly) {
+        for (unsigned i = 0; i < m_currentRun; ++i)
+            leftmostGlyph += m_complexTextRuns[i]->glyphCount();
+        return m_currentRun;
+    }
+
+    if (m_runIndices.isEmpty()) {
+        unsigned firstRun = 0;
+        unsigned firstRunOffset = stringBegin(*m_complexTextRuns[0]);
+        for (unsigned i = 1; i < runCount; ++i) {
+            unsigned offset = stringBegin(*m_complexTextRuns[i]);
+            if (offset < firstRunOffset) {
+                firstRun = i;
+                firstRunOffset = offset;
+            }
+        }
+        m_runIndices.uncheckedAppend(firstRun);
+    }
+
+    while (m_runIndices.size() <= m_currentRun) {
+        unsigned offset = stringEnd(*m_complexTextRuns[m_runIndices.last()]);
+
+        for (unsigned i = 0; i < runCount; ++i) {
+            if (offset == stringBegin(*m_complexTextRuns[i])) {
+                m_runIndices.uncheckedAppend(i);
+                break;
+            }
+        }
+    }
+
+    unsigned currentRunIndex = m_runIndices[m_currentRun];
+    leftmostGlyph = m_glyphCountFromStartToIndex[currentRunIndex];
+    return currentRunIndex;
+}
+
+unsigned ComplexTextController::incrementCurrentRun(unsigned& leftmostGlyph)
+{
+    if (m_isLTROnly) {
+        leftmostGlyph += m_complexTextRuns[m_currentRun++]->glyphCount();
+        return m_currentRun;
+    }
+
+    m_currentRun++;
+    leftmostGlyph = 0;
+    return indexOfCurrentRun(leftmostGlyph);
+}
+
+float ComplexTextController::runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle iterationStyle) const
+{
+    // FIXME: Instead of dividing the glyph's advance equally between the characters, this
+    // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
+    if (glyphStartOffset == glyphEndOffset) {
+        // When there are multiple glyphs per character we need to advance by the full width of the glyph.
+        ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
+        return 1;
+    }
+
+    if (iterationStyle == ByWholeGlyphs) {
+        if (!oldCharacterInCurrentGlyph)
+            return 1;
+        return 0;
+    }
+
+    return static_cast<float>(m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
+}
+
+void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const Font*>* fallbackFonts)
+{
+    if (offset > m_end)
+        offset = m_end;
+
+    if (offset <= m_currentCharacter) {
+        m_runWidthSoFar = 0;
+        m_numGlyphsSoFar = 0;
+        m_currentRun = 0;
+        m_glyphInCurrentRun = 0;
+        m_characterInCurrentGlyph = 0;
+    }
+
+    m_currentCharacter = offset;
+
+    size_t runCount = m_complexTextRuns.size();
+
+    unsigned indexOfLeftmostGlyphInCurrentRun = 0; // Relative to the beginning of ComplexTextController.
+    unsigned currentRunIndex = indexOfCurrentRun(indexOfLeftmostGlyphInCurrentRun);
+    while (m_currentRun < runCount) {
+        const ComplexTextRun& complexTextRun = *m_complexTextRuns[currentRunIndex];
+        bool ltr = complexTextRun.isLTR();
+        unsigned glyphCount = complexTextRun.glyphCount();
+        unsigned glyphIndexIntoCurrentRun = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
+        unsigned glyphIndexIntoComplexTextController = indexOfLeftmostGlyphInCurrentRun + glyphIndexIntoCurrentRun;
+        if (fallbackFonts && &complexTextRun.font() != &m_font.primaryFont())
+            fallbackFonts->add(&complexTextRun.font());
+
+        // We must store the initial advance for the first glyph we are going to draw.
+        // When leftmostGlyph is 0, it represents the first glyph to draw, taking into
+        // account the text direction.
+        if (!indexOfLeftmostGlyphInCurrentRun && glyphBuffer)
+            glyphBuffer->setInitialAdvance(GlyphBufferAdvance(complexTextRun.initialAdvance().width(), complexTextRun.initialAdvance().height()));
+
+        while (m_glyphInCurrentRun < glyphCount) {
+            unsigned glyphStartOffset = complexTextRun.indexAt(glyphIndexIntoCurrentRun);
+            unsigned glyphEndOffset;
+            if (complexTextRun.isMonotonic()) {
+                if (ltr)
+                    glyphEndOffset = std::max(glyphStartOffset, glyphIndexIntoCurrentRun + 1 < glyphCount ? complexTextRun.indexAt(glyphIndexIntoCurrentRun + 1) : complexTextRun.indexEnd());
+                else
+                    glyphEndOffset = std::max(glyphStartOffset, glyphIndexIntoCurrentRun > 0 ? complexTextRun.indexAt(glyphIndexIntoCurrentRun - 1) : complexTextRun.indexEnd());
+            } else
+                glyphEndOffset = complexTextRun.endOffsetAt(glyphIndexIntoCurrentRun);
+
+            FloatSize adjustedBaseAdvance = m_adjustedBaseAdvances[glyphIndexIntoComplexTextController];
+
+            if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
+                return;
+
+            if (glyphBuffer && !m_characterInCurrentGlyph) {
+                auto currentGlyphOrigin = glyphOrigin(glyphIndexIntoComplexTextController);
+                GlyphBufferAdvance paintAdvance(adjustedBaseAdvance);
+                if (!glyphIndexIntoCurrentRun) {
+                    // The first layout advance of every run includes the "initial layout advance." 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()));
+                }
+                paintAdvance.setWidth(paintAdvance.width() + glyphOrigin(glyphIndexIntoComplexTextController + 1).x() - currentGlyphOrigin.x());
+                paintAdvance.setHeight(paintAdvance.height() + glyphOrigin(glyphIndexIntoComplexTextController + 1).y() - currentGlyphOrigin.y());
+                if (glyphIndexIntoCurrentRun == glyphCount - 1 && currentRunIndex + 1 < 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]->initialAdvance().width());
+                    paintAdvance.setHeight(paintAdvance.height() - glyphOrigin(glyphIndexIntoComplexTextController + 1).y() + m_complexTextRuns[currentRunIndex + 1]->initialAdvance().height());
+                }
+                paintAdvance.setHeight(-paintAdvance.height()); // Increasing y points down
+                glyphBuffer->add(m_adjustedGlyphs[glyphIndexIntoComplexTextController], &complexTextRun.font(), paintAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
+            }
+
+            unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
+            m_characterInCurrentGlyph = std::min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
+            m_runWidthSoFar += adjustedBaseAdvance.width() * runWidthSoFarFraction(glyphStartOffset, glyphEndOffset, oldCharacterInCurrentGlyph, iterationStyle);
+
+            if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
+                return;
+
+            m_numGlyphsSoFar++;
+            m_glyphInCurrentRun++;
+            m_characterInCurrentGlyph = 0;
+            if (ltr) {
+                glyphIndexIntoCurrentRun++;
+                glyphIndexIntoComplexTextController++;
+            } else {
+                glyphIndexIntoCurrentRun--;
+                glyphIndexIntoComplexTextController--;
+            }
+        }
+        currentRunIndex = incrementCurrentRun(indexOfLeftmostGlyphInCurrentRun);
+        m_glyphInCurrentRun = 0;
+    }
+}
+
+static inline std::pair<bool, bool> expansionLocation(bool ideograph, bool treatAsSpace, bool ltr, bool isAfterExpansion, bool forbidLeadingExpansion, bool forbidTrailingExpansion, bool forceLeadingExpansion, bool forceTrailingExpansion)
+{
+    bool expandLeft = ideograph;
+    bool expandRight = ideograph;
+    if (treatAsSpace) {
+        if (ltr)
+            expandRight = true;
+        else
+            expandLeft = true;
+    }
+    if (isAfterExpansion)
+        expandLeft = false;
+    ASSERT(!forbidLeadingExpansion || !forceLeadingExpansion);
+    ASSERT(!forbidTrailingExpansion || !forceTrailingExpansion);
+    if (forbidLeadingExpansion)
+        expandLeft = false;
+    if (forbidTrailingExpansion)
+        expandRight = false;
+    if (forceLeadingExpansion)
+        expandLeft = true;
+    if (forceTrailingExpansion)
+        expandRight = true;
+    return std::make_pair(expandLeft, expandRight);
+}
+
+void ComplexTextController::adjustGlyphsAndAdvances()
+{
+    bool afterExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForbidLeadingExpansion;
+    float widthSinceLastCommit = 0;
+    size_t runCount = m_complexTextRuns.size();
+    bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled();
+    bool runForcesLeadingExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForceLeadingExpansion;
+    bool runForcesTrailingExpansion = (m_run.expansionBehavior() & TrailingExpansionMask) == ForceTrailingExpansion;
+    bool runForbidsLeadingExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForbidLeadingExpansion;
+    bool runForbidsTrailingExpansion = (m_run.expansionBehavior() & TrailingExpansionMask) == ForbidTrailingExpansion;
+
+    // We are iterating in glyph order, not string order. Compare this to WidthIterator::advanceInternal()
+    for (size_t runIndex = 0; runIndex < runCount; ++runIndex) {
+        ComplexTextRun& complexTextRun = *m_complexTextRuns[runIndex];
+        unsigned glyphCount = complexTextRun.glyphCount();
+        const Font& font = complexTextRun.font();
+
+        if (!complexTextRun.isLTR())
+            m_isLTROnly = false;
+
+        const CGGlyph* glyphs = complexTextRun.glyphs();
+        const FloatSize* advances = complexTextRun.baseAdvances();
+
+        bool lastRun = runIndex + 1 == runCount;
+        float spaceWidth = font.spaceWidth() - font.syntheticBoldOffset();
+        const UChar* cp = complexTextRun.characters();
+        FloatPoint glyphOrigin;
+        unsigned lastCharacterIndex = m_run.ltr() ? std::numeric_limits<unsigned>::min() : std::numeric_limits<unsigned>::max();
+        bool isMonotonic = true;
+
+        for (unsigned i = 0; i < glyphCount; i++) {
+            unsigned characterIndex = complexTextRun.indexAt(i);
+            if (m_run.ltr()) {
+                if (characterIndex < lastCharacterIndex)
+                    isMonotonic = false;
+            } else {
+                if (characterIndex > lastCharacterIndex)
+                    isMonotonic = false;
+            }
+            UChar ch = *(cp + characterIndex);
+            bool lastGlyph = lastRun && i + 1 == glyphCount;
+            UChar nextCh;
+            if (lastGlyph)
+                nextCh = ' ';
+            else if (i + 1 < glyphCount)
+                nextCh = *(cp + complexTextRun.indexAt(i + 1));
+            else
+                nextCh = *(m_complexTextRuns[runIndex + 1]->characters() + m_complexTextRuns[runIndex + 1]->indexAt(0));
+
+            bool treatAsSpace = FontCascade::treatAsSpace(ch);
+            CGGlyph glyph = treatAsSpace ? font.spaceGlyph() : glyphs[i];
+            FloatSize advance = treatAsSpace ? FloatSize(spaceWidth, advances[i].height()) : advances[i];
+
+            if (ch == '\t' && m_run.allowTabs())
+                advance.setWidth(m_font.tabWidth(font, m_run.tabSize(), m_run.xPos() + m_totalWidth + widthSinceLastCommit));
+            else if (FontCascade::treatAsZeroWidthSpace(ch) && !treatAsSpace) {
+                advance.setWidth(0);
+                glyph = font.spaceGlyph();
+            }
+
+            if (!i) {
+                advance.expand(complexTextRun.initialAdvance().width(), complexTextRun.initialAdvance().height());
+                if (auto* origins = complexTextRun.glyphOrigins())
+                    advance.expand(-origins[0].x(), -origins[0].y());
+            }
+
+            advance.expand(font.syntheticBoldOffset(), 0);
+
+            if (hasExtraSpacing) {
+                // If we're a glyph with an advance, add in letter-spacing.
+                // That way we weed out zero width lurkers. This behavior matches the fast text code path.
+                if (advance.width())
+                    advance.expand(m_font.letterSpacing(), 0);
+
+                unsigned characterIndexInRun = characterIndex + complexTextRun.stringLocation();
+                bool isFirstCharacter = !(characterIndex + complexTextRun.stringLocation());
+                bool isLastCharacter = characterIndexInRun + 1 == m_run.length() || (U16_IS_LEAD(ch) && characterIndexInRun + 2 == m_run.length() && U16_IS_TRAIL(*(cp + characterIndex + 1)));
+
+                bool forceLeadingExpansion = false; // On the left, regardless of m_run.ltr()
+                bool forceTrailingExpansion = false; // On the right, regardless of m_run.ltr()
+                bool forbidLeadingExpansion = false;
+                bool forbidTrailingExpansion = false;
+                if (runForcesLeadingExpansion)
+                    forceLeadingExpansion = m_run.ltr() ? isFirstCharacter : isLastCharacter;
+                if (runForcesTrailingExpansion)
+                    forceTrailingExpansion = m_run.ltr() ? isLastCharacter : isFirstCharacter;
+                if (runForbidsLeadingExpansion)
+                    forbidLeadingExpansion = m_run.ltr() ? isFirstCharacter : isLastCharacter;
+                if (runForbidsTrailingExpansion)
+                    forbidTrailingExpansion = m_run.ltr() ? isLastCharacter : isFirstCharacter;
+                // Handle justification and word-spacing.
+                bool ideograph = FontCascade::isCJKIdeographOrSymbol(ch);
+                if (treatAsSpace || ideograph || forceLeadingExpansion || forceTrailingExpansion) {
+                    // Distribute the run's total expansion evenly over all expansion opportunities in the run.
+                    if (m_expansion) {
+                        bool expandLeft, expandRight;
+                        std::tie(expandLeft, expandRight) = expansionLocation(ideograph, treatAsSpace, m_run.ltr(), afterExpansion, forbidLeadingExpansion, forbidTrailingExpansion, forceLeadingExpansion, forceTrailingExpansion);
+                        m_expansion -= m_expansionPerOpportunity;
+                        advance.expand(m_expansionPerOpportunity, 0);
+                        if (expandLeft) {
+                            // Increase previous width
+                            if (m_adjustedBaseAdvances.isEmpty())
+                                complexTextRun.growInitialAdvanceHorizontally(m_expansionPerOpportunity);
+                            else
+                                m_adjustedBaseAdvances.last().expand(m_expansionPerOpportunity, 0);
+                        }
+                        if (expandRight)
+                            afterExpansion = true;
+                    } else
+                        afterExpansion = false;
+
+                    // Account for word-spacing.
+                    if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || runIndex > 0) && m_font.wordSpacing())
+                        advance.expand(m_font.wordSpacing(), 0);
+                } else
+                    afterExpansion = false;
+            }
+
+            widthSinceLastCommit += advance.width();
+
+            // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
+            if (m_forTextEmphasis && (!FontCascade::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
+                glyph = 0;
+
+            m_adjustedBaseAdvances.append(advance);
+            if (auto* origins = complexTextRun.glyphOrigins()) {
+                ASSERT(m_glyphOrigins.size() < m_adjustedBaseAdvances.size());
+                m_glyphOrigins.grow(m_adjustedBaseAdvances.size());
+                m_glyphOrigins[m_glyphOrigins.size() - 1] = origins[i];
+                ASSERT(m_glyphOrigins.size() == m_adjustedBaseAdvances.size());
+            }
+            m_adjustedGlyphs.append(glyph);
+            
+            FloatRect glyphBounds = font.boundsForGlyph(glyph);
+            glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
+            m_minGlyphBoundingBoxX = std::min(m_minGlyphBoundingBoxX, glyphBounds.x());
+            m_maxGlyphBoundingBoxX = std::max(m_maxGlyphBoundingBoxX, glyphBounds.maxX());
+            m_minGlyphBoundingBoxY = std::min(m_minGlyphBoundingBoxY, glyphBounds.y());
+            m_maxGlyphBoundingBoxY = std::max(m_maxGlyphBoundingBoxY, glyphBounds.maxY());
+            glyphOrigin.move(advance);
+            
+            lastCharacterIndex = characterIndex;
+        }
+        if (!isMonotonic)
+            complexTextRun.setIsNonMonotonic();
+    }
+
+    m_totalWidth += widthSinceLastCommit;
+}
+
+} // namespace WebCore

Copied: trunk/Source/WebCore/platform/graphics/ComplexTextController.h (from rev 211775, trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h) (0 => 211776)


--- trunk/Source/WebCore/platform/graphics/ComplexTextController.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/ComplexTextController.h	2017-02-07 08:14:06 UTC (rev 211776)
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "FloatPoint.h"
+#include "GlyphBuffer.h"
+#include <wtf/HashSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+#define USE_LAYOUT_SPECIFIC_ADVANCES ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000))
+
+typedef unsigned short CGGlyph;
+
+typedef const struct __CTRun * CTRunRef;
+typedef const struct __CTLine * CTLineRef;
+
+namespace WebCore {
+
+class FontCascade;
+class Font;
+class TextRun;
+
+enum GlyphIterationStyle { IncludePartialGlyphs, ByWholeGlyphs };
+
+// See https://trac.webkit.org/wiki/ComplexTextController for more information about ComplexTextController.
+class ComplexTextController {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    ComplexTextController(const FontCascade&, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const Font*>* fallbackFonts = 0, bool forTextEmphasis = false);
+
+    class ComplexTextRun;
+    WEBCORE_EXPORT ComplexTextController(const FontCascade&, const TextRun&, Vector<Ref<ComplexTextRun>>&);
+
+    // Advance and emit glyphs up to the specified character.
+    WEBCORE_EXPORT void advance(unsigned to, GlyphBuffer* = nullptr, GlyphIterationStyle = IncludePartialGlyphs, HashSet<const Font*>* fallbackFonts = nullptr);
+
+    // Compute the character offset for a given x coordinate.
+    unsigned offsetForPosition(float x, bool includePartialGlyphs);
+
+    // Returns the width of everything we've consumed so far.
+    float runWidthSoFar() const { return m_runWidthSoFar; }
+
+    float totalWidth() const { return m_totalWidth; }
+
+    float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
+    float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; }
+    float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
+    float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
+
+    class ComplexTextRun : public RefCounted<ComplexTextRun> {
+    public:
+        static Ref<ComplexTextRun> create(CTRunRef ctRun, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd)
+        {
+            return adoptRef(*new ComplexTextRun(ctRun, font, characters, stringLocation, stringLength, indexBegin, indexEnd));
+        }
+
+        static Ref<ComplexTextRun> create(const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr)
+        {
+            return adoptRef(*new ComplexTextRun(font, characters, stringLocation, stringLength, indexBegin, indexEnd, ltr));
+        }
+
+        static Ref<ComplexTextRun> create(const Vector<FloatSize>& advances, const Vector<FloatPoint>& origins, const Vector<Glyph>& glyphs, const Vector<unsigned>& stringIndices, FloatSize initialAdvance, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr)
+        {
+            return adoptRef(*new ComplexTextRun(advances, origins, glyphs, stringIndices, initialAdvance, font, characters, stringLocation, stringLength, indexBegin, indexEnd, ltr));
+        }
+
+        unsigned glyphCount() const { return m_glyphCount; }
+        const Font& font() const { return m_font; }
+        const UChar* characters() const { return m_characters; }
+        unsigned stringLocation() const { return m_stringLocation; }
+        unsigned stringLength() const { return m_stringLength; }
+        ALWAYS_INLINE unsigned indexAt(unsigned) const;
+        unsigned indexBegin() const { return m_indexBegin; }
+        unsigned indexEnd() const { return m_indexEnd; }
+        unsigned endOffsetAt(unsigned i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; }
+        const CGGlyph* glyphs() const { return m_glyphs.data(); }
+
+        /*
+         * This is the format of the information CoreText gives us about each run:
+         *
+         *                                        ----->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):
+         *
+         *                                        ----->X------------------------->X------------------------->X
+         *                                       /            (Paint advance)            (Paint advance)       \
+         *                                      /                                                               \
+         *                   (Initial advance) /                                                                 \ (Paint advance)
+         *                  -------------------                                                                   ----------------
+         *                 /                                                                                                      \
+         *                X--------------------------------------------------X--------------------------X--------------------------X
+         * (text position ^)                (layout advance)                       (layout advance)           (layout advance)
+         */
+        void growInitialAdvanceHorizontally(float delta) { m_initialAdvance.expand(delta, 0); }
+        FloatSize initialAdvance() const { return m_initialAdvance; }
+        const FloatSize* baseAdvances() const { return m_baseAdvances.data(); }
+        const FloatPoint* glyphOrigins() const { return m_glyphOrigins.size() == glyphCount() ? m_glyphOrigins.data() : nullptr; }
+        bool isLTR() const { return m_isLTR; }
+        bool isMonotonic() const { return m_isMonotonic; }
+        void setIsNonMonotonic();
+
+    private:
+        ComplexTextRun(CTRunRef, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd);
+        ComplexTextRun(const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr);
+        WEBCORE_EXPORT ComplexTextRun(const Vector<FloatSize>& advances, const Vector<FloatPoint>& origins, const Vector<Glyph>& glyphs, const Vector<unsigned>& stringIndices, FloatSize initialAdvance, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr);
+
+        Vector<FloatSize, 64> m_baseAdvances;
+        Vector<FloatPoint, 64> m_glyphOrigins;
+        Vector<CGGlyph, 64> m_glyphs;
+        Vector<unsigned, 64> m_glyphEndOffsets;
+        Vector<unsigned, 64> m_coreTextIndices;
+        FloatSize m_initialAdvance;
+        const Font& m_font;
+        const UChar* m_characters;
+        unsigned m_stringLength;
+        unsigned m_indexBegin;
+        unsigned m_indexEnd;
+        unsigned m_glyphCount;
+        unsigned m_stringLocation;
+        bool m_isLTR;
+        bool m_isMonotonic { true };
+    };
+private:
+    void computeExpansionOpportunity();
+    void finishConstruction();
+    
+    static unsigned stringBegin(const ComplexTextRun& run) { return run.stringLocation() + run.indexBegin(); }
+    static unsigned stringEnd(const ComplexTextRun& run) { return run.stringLocation() + run.indexEnd(); }
+
+    void collectComplexTextRuns();
+
+    void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const Font*);
+    void adjustGlyphsAndAdvances();
+
+    unsigned indexOfCurrentRun(unsigned& leftmostGlyph);
+    unsigned incrementCurrentRun(unsigned& leftmostGlyph);
+
+    float runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle) const;
+
+    FloatPoint glyphOrigin(unsigned index) const { return index < m_glyphOrigins.size() ? m_glyphOrigins[index] : FloatPoint(); }
+
+    Vector<FloatSize, 256> m_adjustedBaseAdvances;
+    Vector<FloatPoint, 256> m_glyphOrigins;
+    Vector<CGGlyph, 256> m_adjustedGlyphs;
+
+    Vector<UChar, 256> m_smallCapsBuffer;
+
+    // There is a 3-level hierarchy here. At the top, we are interested in m_run.string(). We partition that string
+    // into Lines, each of which is a sequence of characters which should use the same Font. Core Text then partitions
+    // the Line into ComplexTextRuns.
+    // ComplexTextRun::stringLocation() and ComplexTextRun::stringLength() refer to the offset and length of the Line
+    // relative to m_run.string(). ComplexTextRun::indexAt() returns to the offset of a codepoint relative to
+    // its Line. ComplexTextRun::glyphs() and ComplexTextRun::advances() refer to glyphs relative to the ComplexTextRun.
+    // The length of the entire TextRun is m_run.length()
+    Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
+
+    // The initial capacity of these vectors was selected as being the smallest power of two greater than
+    // the average (3.5) plus one standard deviation (7.5) of nonzero sizes used on Arabic Wikipedia.
+    Vector<unsigned, 16> m_runIndices;
+    Vector<unsigned, 16> m_glyphCountFromStartToIndex;
+
+    Vector<RetainPtr<CTLineRef>> m_coreTextLines;
+
+    Vector<String> m_stringsFor8BitRuns;
+
+    HashSet<const Font*>* m_fallbackFonts { nullptr };
+
+    const FontCascade& m_font;
+    const TextRun& m_run;
+
+    unsigned m_currentCharacter { 0 };
+    unsigned m_end { 0 };
+
+    float m_totalWidth { 0 };
+    float m_runWidthSoFar { 0 };
+    unsigned m_numGlyphsSoFar { 0 };
+    unsigned m_currentRun { 0 };
+    unsigned m_glyphInCurrentRun { 0 };
+    unsigned m_characterInCurrentGlyph { 0 };
+    float m_expansion { 0 };
+    float m_expansionPerOpportunity { 0 };
+
+    float m_minGlyphBoundingBoxX { std::numeric_limits<float>::max() };
+    float m_maxGlyphBoundingBoxX { std::numeric_limits<float>::min() };
+    float m_minGlyphBoundingBoxY { std::numeric_limits<float>::max() };
+    float m_maxGlyphBoundingBoxY { std::numeric_limits<float>::min() };
+
+    bool m_isLTROnly { true };
+    bool m_mayUseNaturalWritingDirection { false };
+    bool m_forTextEmphasis { false };
+};
+
+} // namespace WebCore

Deleted: trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp (211775 => 211776)


--- trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp	2017-02-07 06:45:43 UTC (rev 211775)
+++ trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp	2017-02-07 08:14:06 UTC (rev 211776)
@@ -1,833 +0,0 @@
-/*
- * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "ComplexTextController.h"
-
-#include "CharacterProperties.h"
-#include "FloatSize.h"
-#include "FontCascade.h"
-#include "RenderBlock.h"
-#include "RenderText.h"
-#include "TextRun.h"
-#include <unicode/ubrk.h>
-#include <wtf/Optional.h>
-#include <wtf/StdLibExtras.h>
-#include <wtf/text/TextBreakIterator.h>
-#include <wtf/unicode/CharacterNames.h>
-
-#if PLATFORM(IOS)
-#include <CoreText/CoreText.h>
-#endif
-
-#if PLATFORM(MAC)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace WebCore {
-
-class TextLayout {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    static bool isNeeded(RenderText& text, const FontCascade& font)
-    {
-        TextRun run = RenderBlock::constructTextRun(text, text.style());
-        return font.codePath(run) == FontCascade::Complex;
-    }
-
-    TextLayout(RenderText& text, const FontCascade& font, float xPos)
-        : m_font(font)
-        , m_run(constructTextRun(text, xPos))
-        , m_controller(std::make_unique<ComplexTextController>(m_font, m_run, true))
-    {
-    }
-
-    float width(unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts)
-    {
-        m_controller->advance(from, 0, ByWholeGlyphs, fallbackFonts);
-        float beforeWidth = m_controller->runWidthSoFar();
-        if (m_font.wordSpacing() && from && FontCascade::treatAsSpace(m_run[from]))
-            beforeWidth += m_font.wordSpacing();
-        m_controller->advance(from + len, 0, ByWholeGlyphs, fallbackFonts);
-        float afterWidth = m_controller->runWidthSoFar();
-        return afterWidth - beforeWidth;
-    }
-
-private:
-    static TextRun constructTextRun(RenderText& text, float xPos)
-    {
-        TextRun run = RenderBlock::constructTextRun(text, text.style());
-        run.setCharactersLength(text.textLength());
-        ASSERT(run.charactersLength() >= run.length());
-        run.setXPos(xPos);
-        return run;
-    }
-
-    // ComplexTextController has only references to its FontCascade and TextRun so they must be kept alive here.
-    FontCascade m_font;
-    TextRun m_run;
-    std::unique_ptr<ComplexTextController> m_controller;
-};
-
-void TextLayoutDeleter::operator()(TextLayout* layout) const
-{
-    delete layout;
-}
-
-std::unique_ptr<TextLayout, TextLayoutDeleter> FontCascade::createLayout(RenderText& text, float xPos, bool collapseWhiteSpace) const
-{
-    if (!collapseWhiteSpace || !TextLayout::isNeeded(text, *this))
-        return nullptr;
-    return std::unique_ptr<TextLayout, TextLayoutDeleter>(new TextLayout(text, *this, xPos));
-}
-
-float FontCascade::width(TextLayout& layout, unsigned from, unsigned len, HashSet<const Font*>* fallbackFonts)
-{
-    return layout.width(from, len, fallbackFonts);
-}
-
-void ComplexTextController::computeExpansionOpportunity()
-{
-    if (!m_expansion)
-        m_expansionPerOpportunity = 0;
-    else {
-        unsigned expansionOpportunityCount = FontCascade::expansionOpportunityCount(m_run.text(), m_run.ltr() ? LTR : RTL, m_run.expansionBehavior()).first;
-
-        if (!expansionOpportunityCount)
-            m_expansionPerOpportunity = 0;
-        else
-            m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
-    }
-}
-
-ComplexTextController::ComplexTextController(const FontCascade& font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const Font*>* 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();
-
-    collectComplexTextRuns();
-
-    finishConstruction();
-}
-
-ComplexTextController::ComplexTextController(const FontCascade& font, const TextRun& run, Vector<Ref<ComplexTextRun>>& runs)
-    : m_font(font)
-    , m_run(run)
-    , m_end(run.length())
-    , m_expansion(run.expansion())
-{
-    computeExpansionOpportunity();
-
-    for (auto& run : runs)
-        m_complexTextRuns.append(run.ptr());
-
-    finishConstruction();
-}
-
-void ComplexTextController::finishConstruction()
-{
-    adjustGlyphsAndAdvances();
-
-    if (!m_isLTROnly) {
-        m_runIndices.reserveInitialCapacity(m_complexTextRuns.size());
-
-        m_glyphCountFromStartToIndex.reserveInitialCapacity(m_complexTextRuns.size());
-        unsigned glyphCountSoFar = 0;
-        for (unsigned i = 0; i < m_complexTextRuns.size(); ++i) {
-            m_glyphCountFromStartToIndex.uncheckedAppend(glyphCountSoFar);
-            glyphCountSoFar += m_complexTextRuns[i]->glyphCount();
-        }
-    }
-}
-
-unsigned ComplexTextController::offsetForPosition(float h, bool includePartialGlyphs)
-{
-    if (h >= m_totalWidth)
-        return m_run.ltr() ? m_end : 0;
-
-    if (h < 0)
-        return m_run.ltr() ? 0 : m_end;
-
-    float x = h;
-
-    size_t runCount = m_complexTextRuns.size();
-    unsigned offsetIntoAdjustedGlyphs = 0;
-
-    for (size_t r = 0; r < runCount; ++r) {
-        const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
-        for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
-            unsigned index = offsetIntoAdjustedGlyphs + j;
-            float adjustedAdvance = m_adjustedBaseAdvances[index].width();
-            if (x < adjustedAdvance) {
-                unsigned hitGlyphStart = complexTextRun.indexAt(j);
-                unsigned hitGlyphEnd;
-                if (m_run.ltr())
-                    hitGlyphEnd = std::max(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : complexTextRun.indexEnd());
-                else
-                    hitGlyphEnd = std::max(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.indexEnd());
-
-                // FIXME: Instead of dividing the glyph's advance equally between the characters, this
-                // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
-                unsigned hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
-                unsigned stringLength = complexTextRun.stringLength();
-                UBreakIterator* cursorPositionIterator = cursorMovementIterator(StringView(complexTextRun.characters(), stringLength));
-                unsigned clusterStart;
-                if (ubrk_isBoundary(cursorPositionIterator, hitIndex))
-                    clusterStart = hitIndex;
-                else {
-                    int preceeding = ubrk_preceding(cursorPositionIterator, hitIndex);
-                    clusterStart = preceeding == UBRK_DONE ? 0 : preceeding;
-                }
-
-                if (!includePartialGlyphs)
-                    return complexTextRun.stringLocation() + clusterStart;
-
-                int following = ubrk_following(cursorPositionIterator, hitIndex);
-                unsigned clusterEnd = following == UBRK_DONE ? stringLength : following;
-
-                float clusterWidth;
-                // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
-                // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
-                // reordering and no font fallback should occur within a CTLine.
-                if (clusterEnd - clusterStart > 1) {
-                    clusterWidth = adjustedAdvance;
-                    if (j) {
-                        unsigned firstGlyphBeforeCluster = j - 1;
-                        while (complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
-                            float width = m_adjustedBaseAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width();
-                            clusterWidth += width;
-                            x += width;
-                            if (!firstGlyphBeforeCluster)
-                                break;
-                            firstGlyphBeforeCluster--;
-                        }
-                    }
-                    unsigned firstGlyphAfterCluster = j + 1;
-                    while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
-                        clusterWidth += m_adjustedBaseAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width();
-                        firstGlyphAfterCluster++;
-                    }
-                } else {
-                    clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
-                    x -=  clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
-                }
-                if (x <= clusterWidth / 2)
-                    return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
-                return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
-            }
-            x -= adjustedAdvance;
-        }
-        offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
-    }
-
-    ASSERT_NOT_REACHED();
-    return 0;
-}
-
-// FIXME: We should consider reimplementing this function using ICU to advance by grapheme.
-// The current implementation only considers explicitly emoji sequences and emoji variations.
-static bool advanceByCombiningCharacterSequence(const UChar*& iterator, const UChar* end, UChar32& baseCharacter, unsigned& markCount)
-{
-    ASSERT(iterator < end);
-
-    markCount = 0;
-
-    unsigned i = 0;
-    unsigned remainingCharacters = end - iterator;
-    U16_NEXT(iterator, i, remainingCharacters, baseCharacter);
-    iterator = iterator + i;
-    if (U_IS_SURROGATE(baseCharacter))
-        return false;
-
-    // Consume marks.
-    bool sawEmojiGroupCandidate = isEmojiGroupCandidate(baseCharacter);
-    bool sawJoiner = false;
-    while (iterator < end) {
-        UChar32 nextCharacter;
-        unsigned markLength = 0;
-        bool shouldContinue = false;
-        ASSERT(end >= iterator);
-        U16_NEXT(iterator, markLength, static_cast<unsigned>(end - iterator), nextCharacter);
-
-        if (isVariationSelector(nextCharacter) || isEmojiFitzpatrickModifier(nextCharacter))
-            shouldContinue = true;
-
-        if (sawJoiner && isEmojiGroupCandidate(nextCharacter))
-            shouldContinue = true;
-
-        sawJoiner = false;
-        if (sawEmojiGroupCandidate && nextCharacter == zeroWidthJoiner) {
-            sawJoiner = true;
-            shouldContinue = true;
-        }
-        
-        if (!shouldContinue && !(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
-            break;
-
-        markCount += markLength;
-        iterator += markLength;
-    }
-
-    return true;
-}
-
-// FIXME: Capitalization is language-dependent and context-dependent and should operate on grapheme clusters instead of codepoints.
-static inline std::optional<UChar32> capitalized(UChar32 baseCharacter)
-{
-    if (U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK)
-        return std::nullopt;
-
-    UChar32 uppercaseCharacter = u_toupper(baseCharacter);
-    ASSERT(uppercaseCharacter == baseCharacter || (U_IS_BMP(baseCharacter) == U_IS_BMP(uppercaseCharacter)));
-    if (uppercaseCharacter != baseCharacter)
-        return uppercaseCharacter;
-    return std::nullopt;
-}
-
-static bool shouldSynthesize(bool dontSynthesizeSmallCaps, const Font* nextFont, UChar32 baseCharacter, std::optional<UChar32> capitalizedBase, FontVariantCaps fontVariantCaps, bool engageAllSmallCapsProcessing)
-{
-    if (dontSynthesizeSmallCaps)
-        return false;
-    if (!nextFont || nextFont == Font::systemFallback())
-        return false;
-    if (engageAllSmallCapsProcessing && isASCIISpace(baseCharacter))
-        return false;
-    if (!engageAllSmallCapsProcessing && !capitalizedBase)
-        return false;
-    return !nextFont->variantCapsSupportsCharacterForSynthesis(fontVariantCaps, baseCharacter);
-}
-
-void ComplexTextController::collectComplexTextRuns()
-{
-    if (!m_end)
-        return;
-
-    // We break up glyph run generation for the string by Font.
-    const UChar* cp;
-
-    if (m_run.is8Bit()) {
-        String stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
-        m_stringsFor8BitRuns.append(WTFMove(stringFor8BitRun));
-        cp = m_stringsFor8BitRuns.last().characters16();
-    } else
-        cp = m_run.characters16();
-
-    auto fontVariantCaps = m_font.fontDescription().variantCaps();
-    bool dontSynthesizeSmallCaps = !static_cast<bool>(m_font.fontDescription().fontSynthesis() & FontSynthesisSmallCaps);
-    bool engageAllSmallCapsProcessing = fontVariantCaps == FontVariantCaps::AllSmall || fontVariantCaps == FontVariantCaps::AllPetite;
-    bool engageSmallCapsProcessing = engageAllSmallCapsProcessing || fontVariantCaps == FontVariantCaps::Small || fontVariantCaps == FontVariantCaps::Petite;
-
-    if (engageAllSmallCapsProcessing || engageSmallCapsProcessing)
-        m_smallCapsBuffer.resize(m_end);
-
-    unsigned indexOfFontTransition = 0;
-    const UChar* curr = cp;
-    const UChar* end = cp + m_end;
-
-    const Font* font;
-    const Font* nextFont;
-    const Font* synthesizedFont = nullptr;
-    const Font* smallSynthesizedFont = nullptr;
-
-    unsigned markCount;
-    UChar32 baseCharacter;
-    if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
-        return;
-
-    nextFont = m_font.fontForCombiningCharacterSequence(cp, curr - cp);
-
-    bool isSmallCaps = false;
-    bool nextIsSmallCaps = false;
-
-    auto capitalizedBase = capitalized(baseCharacter);
-    if (shouldSynthesize(dontSynthesizeSmallCaps, nextFont, baseCharacter, capitalizedBase, fontVariantCaps, engageAllSmallCapsProcessing)) {
-        synthesizedFont = &nextFont->noSynthesizableFeaturesFont();
-        smallSynthesizedFont = synthesizedFont->smallCapsFont(m_font.fontDescription());
-        UChar32 characterToWrite = capitalizedBase ? capitalizedBase.value() : cp[0];
-        unsigned characterIndex = 0;
-        U16_APPEND_UNSAFE(m_smallCapsBuffer, characterIndex, characterToWrite);
-        for (unsigned i = characterIndex; cp + i < curr; ++i)
-            m_smallCapsBuffer[i] = cp[i];
-        nextIsSmallCaps = true;
-    }
-
-    while (curr < end) {
-        font = nextFont;
-        isSmallCaps = nextIsSmallCaps;
-        unsigned index = curr - cp;
-
-        if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount))
-            return;
-
-        if (synthesizedFont) {
-            if (auto capitalizedBase = capitalized(baseCharacter)) {
-                unsigned characterIndex = index;
-                U16_APPEND_UNSAFE(m_smallCapsBuffer, characterIndex, capitalizedBase.value());
-                for (unsigned i = 0; i < markCount; ++i)
-                    m_smallCapsBuffer[i + characterIndex] = cp[i + characterIndex];
-                nextIsSmallCaps = true;
-            } else {
-                if (engageAllSmallCapsProcessing) {
-                    for (unsigned i = 0; i < curr - cp - index; ++i)
-                        m_smallCapsBuffer[index + i] = cp[index + i];
-                }
-                nextIsSmallCaps = engageAllSmallCapsProcessing;
-            }
-        }
-
-        if (baseCharacter == zeroWidthJoiner)
-            nextFont = font;
-        else
-            nextFont = m_font.fontForCombiningCharacterSequence(cp + index, curr - cp - index);
-
-        capitalizedBase = capitalized(baseCharacter);
-        if (!synthesizedFont && shouldSynthesize(dontSynthesizeSmallCaps, nextFont, baseCharacter, capitalizedBase, fontVariantCaps, engageAllSmallCapsProcessing)) {
-            // Rather than synthesize each character individually, we should synthesize the entire "run" if any character requires synthesis.
-            synthesizedFont = &nextFont->noSynthesizableFeaturesFont();
-            smallSynthesizedFont = synthesizedFont->smallCapsFont(m_font.fontDescription());
-            nextIsSmallCaps = true;
-            curr = cp + indexOfFontTransition;
-            continue;
-        }
-
-        if (nextFont != font || nextIsSmallCaps != isSmallCaps) {
-            unsigned itemLength = index - indexOfFontTransition;
-            if (itemLength) {
-                unsigned itemStart = indexOfFontTransition;
-                if (synthesizedFont) {
-                    if (isSmallCaps)
-                        collectComplexTextRunsForCharacters(m_smallCapsBuffer.data() + itemStart, itemLength, itemStart, smallSynthesizedFont);
-                    else
-                        collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, synthesizedFont);
-                } else
-                    collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, font);
-                if (nextFont != font) {
-                    synthesizedFont = nullptr;
-                    smallSynthesizedFont = nullptr;
-                    nextIsSmallCaps = false;
-                }
-            }
-            indexOfFontTransition = index;
-        }
-    }
-
-    ASSERT(m_end >= indexOfFontTransition);
-    unsigned itemLength = m_end - indexOfFontTransition;
-    if (itemLength) {
-        unsigned itemStart = indexOfFontTransition;
-        if (synthesizedFont) {
-            if (nextIsSmallCaps)
-                collectComplexTextRunsForCharacters(m_smallCapsBuffer.data() + itemStart, itemLength, itemStart, smallSynthesizedFont);
-            else
-                collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, synthesizedFont);
-        } else
-            collectComplexTextRunsForCharacters(cp + itemStart, itemLength, itemStart, nextFont);
-    }
-
-    if (!m_run.ltr())
-        m_complexTextRuns.reverse();
-}
-
-unsigned ComplexTextController::ComplexTextRun::indexAt(unsigned i) const
-{
-    ASSERT(i < m_glyphCount);
-
-    return m_coreTextIndices[i];
-}
-
-void ComplexTextController::ComplexTextRun::setIsNonMonotonic()
-{
-    ASSERT(m_isMonotonic);
-    m_isMonotonic = false;
-
-    Vector<bool, 64> mappedIndices(m_stringLength, false);
-    for (unsigned i = 0; i < m_glyphCount; ++i) {
-        ASSERT(indexAt(i) < m_stringLength);
-        mappedIndices[indexAt(i)] = true;
-    }
-
-    m_glyphEndOffsets.grow(m_glyphCount);
-    for (unsigned i = 0; i < m_glyphCount; ++i) {
-        unsigned nextMappedIndex = m_indexEnd;
-        for (unsigned j = indexAt(i) + 1; j < m_stringLength; ++j) {
-            if (mappedIndices[j]) {
-                nextMappedIndex = j;
-                break;
-            }
-        }
-        m_glyphEndOffsets[i] = nextMappedIndex;
-    }
-}
-
-unsigned ComplexTextController::indexOfCurrentRun(unsigned& leftmostGlyph)
-{
-    leftmostGlyph = 0;
-    
-    size_t runCount = m_complexTextRuns.size();
-    if (m_currentRun >= runCount)
-        return runCount;
-
-    if (m_isLTROnly) {
-        for (unsigned i = 0; i < m_currentRun; ++i)
-            leftmostGlyph += m_complexTextRuns[i]->glyphCount();
-        return m_currentRun;
-    }
-
-    if (m_runIndices.isEmpty()) {
-        unsigned firstRun = 0;
-        unsigned firstRunOffset = stringBegin(*m_complexTextRuns[0]);
-        for (unsigned i = 1; i < runCount; ++i) {
-            unsigned offset = stringBegin(*m_complexTextRuns[i]);
-            if (offset < firstRunOffset) {
-                firstRun = i;
-                firstRunOffset = offset;
-            }
-        }
-        m_runIndices.uncheckedAppend(firstRun);
-    }
-
-    while (m_runIndices.size() <= m_currentRun) {
-        unsigned offset = stringEnd(*m_complexTextRuns[m_runIndices.last()]);
-
-        for (unsigned i = 0; i < runCount; ++i) {
-            if (offset == stringBegin(*m_complexTextRuns[i])) {
-                m_runIndices.uncheckedAppend(i);
-                break;
-            }
-        }
-    }
-
-    unsigned currentRunIndex = m_runIndices[m_currentRun];
-    leftmostGlyph = m_glyphCountFromStartToIndex[currentRunIndex];
-    return currentRunIndex;
-}
-
-unsigned ComplexTextController::incrementCurrentRun(unsigned& leftmostGlyph)
-{
-    if (m_isLTROnly) {
-        leftmostGlyph += m_complexTextRuns[m_currentRun++]->glyphCount();
-        return m_currentRun;
-    }
-
-    m_currentRun++;
-    leftmostGlyph = 0;
-    return indexOfCurrentRun(leftmostGlyph);
-}
-
-float ComplexTextController::runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle iterationStyle) const
-{
-    // FIXME: Instead of dividing the glyph's advance equally between the characters, this
-    // could use the glyph's "ligature carets". This is available in CoreText via CTFontGetLigatureCaretPositions().
-    if (glyphStartOffset == glyphEndOffset) {
-        // When there are multiple glyphs per character we need to advance by the full width of the glyph.
-        ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
-        return 1;
-    }
-
-    if (iterationStyle == ByWholeGlyphs) {
-        if (!oldCharacterInCurrentGlyph)
-            return 1;
-        return 0;
-    }
-
-    return static_cast<float>(m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
-}
-
-void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle, HashSet<const Font*>* fallbackFonts)
-{
-    if (offset > m_end)
-        offset = m_end;
-
-    if (offset <= m_currentCharacter) {
-        m_runWidthSoFar = 0;
-        m_numGlyphsSoFar = 0;
-        m_currentRun = 0;
-        m_glyphInCurrentRun = 0;
-        m_characterInCurrentGlyph = 0;
-    }
-
-    m_currentCharacter = offset;
-
-    size_t runCount = m_complexTextRuns.size();
-
-    unsigned indexOfLeftmostGlyphInCurrentRun = 0; // Relative to the beginning of ComplexTextController.
-    unsigned currentRunIndex = indexOfCurrentRun(indexOfLeftmostGlyphInCurrentRun);
-    while (m_currentRun < runCount) {
-        const ComplexTextRun& complexTextRun = *m_complexTextRuns[currentRunIndex];
-        bool ltr = complexTextRun.isLTR();
-        unsigned glyphCount = complexTextRun.glyphCount();
-        unsigned glyphIndexIntoCurrentRun = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
-        unsigned glyphIndexIntoComplexTextController = indexOfLeftmostGlyphInCurrentRun + glyphIndexIntoCurrentRun;
-        if (fallbackFonts && &complexTextRun.font() != &m_font.primaryFont())
-            fallbackFonts->add(&complexTextRun.font());
-
-        // We must store the initial advance for the first glyph we are going to draw.
-        // When leftmostGlyph is 0, it represents the first glyph to draw, taking into
-        // account the text direction.
-        if (!indexOfLeftmostGlyphInCurrentRun && glyphBuffer)
-            glyphBuffer->setInitialAdvance(GlyphBufferAdvance(complexTextRun.initialAdvance().width(), complexTextRun.initialAdvance().height()));
-
-        while (m_glyphInCurrentRun < glyphCount) {
-            unsigned glyphStartOffset = complexTextRun.indexAt(glyphIndexIntoCurrentRun);
-            unsigned glyphEndOffset;
-            if (complexTextRun.isMonotonic()) {
-                if (ltr)
-                    glyphEndOffset = std::max(glyphStartOffset, glyphIndexIntoCurrentRun + 1 < glyphCount ? complexTextRun.indexAt(glyphIndexIntoCurrentRun + 1) : complexTextRun.indexEnd());
-                else
-                    glyphEndOffset = std::max(glyphStartOffset, glyphIndexIntoCurrentRun > 0 ? complexTextRun.indexAt(glyphIndexIntoCurrentRun - 1) : complexTextRun.indexEnd());
-            } else
-                glyphEndOffset = complexTextRun.endOffsetAt(glyphIndexIntoCurrentRun);
-
-            FloatSize adjustedBaseAdvance = m_adjustedBaseAdvances[glyphIndexIntoComplexTextController];
-
-            if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
-                return;
-
-            if (glyphBuffer && !m_characterInCurrentGlyph) {
-                auto currentGlyphOrigin = glyphOrigin(glyphIndexIntoComplexTextController);
-                GlyphBufferAdvance paintAdvance(adjustedBaseAdvance);
-                if (!glyphIndexIntoCurrentRun) {
-                    // The first layout advance of every run includes the "initial layout advance." 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()));
-                }
-                paintAdvance.setWidth(paintAdvance.width() + glyphOrigin(glyphIndexIntoComplexTextController + 1).x() - currentGlyphOrigin.x());
-                paintAdvance.setHeight(paintAdvance.height() + glyphOrigin(glyphIndexIntoComplexTextController + 1).y() - currentGlyphOrigin.y());
-                if (glyphIndexIntoCurrentRun == glyphCount - 1 && currentRunIndex + 1 < 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]->initialAdvance().width());
-                    paintAdvance.setHeight(paintAdvance.height() - glyphOrigin(glyphIndexIntoComplexTextController + 1).y() + m_complexTextRuns[currentRunIndex + 1]->initialAdvance().height());
-                }
-                paintAdvance.setHeight(-paintAdvance.height()); // Increasing y points down
-                glyphBuffer->add(m_adjustedGlyphs[glyphIndexIntoComplexTextController], &complexTextRun.font(), paintAdvance, complexTextRun.indexAt(m_glyphInCurrentRun));
-            }
-
-            unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
-            m_characterInCurrentGlyph = std::min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
-            m_runWidthSoFar += adjustedBaseAdvance.width() * runWidthSoFarFraction(glyphStartOffset, glyphEndOffset, oldCharacterInCurrentGlyph, iterationStyle);
-
-            if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
-                return;
-
-            m_numGlyphsSoFar++;
-            m_glyphInCurrentRun++;
-            m_characterInCurrentGlyph = 0;
-            if (ltr) {
-                glyphIndexIntoCurrentRun++;
-                glyphIndexIntoComplexTextController++;
-            } else {
-                glyphIndexIntoCurrentRun--;
-                glyphIndexIntoComplexTextController--;
-            }
-        }
-        currentRunIndex = incrementCurrentRun(indexOfLeftmostGlyphInCurrentRun);
-        m_glyphInCurrentRun = 0;
-    }
-}
-
-static inline std::pair<bool, bool> expansionLocation(bool ideograph, bool treatAsSpace, bool ltr, bool isAfterExpansion, bool forbidLeadingExpansion, bool forbidTrailingExpansion, bool forceLeadingExpansion, bool forceTrailingExpansion)
-{
-    bool expandLeft = ideograph;
-    bool expandRight = ideograph;
-    if (treatAsSpace) {
-        if (ltr)
-            expandRight = true;
-        else
-            expandLeft = true;
-    }
-    if (isAfterExpansion)
-        expandLeft = false;
-    ASSERT(!forbidLeadingExpansion || !forceLeadingExpansion);
-    ASSERT(!forbidTrailingExpansion || !forceTrailingExpansion);
-    if (forbidLeadingExpansion)
-        expandLeft = false;
-    if (forbidTrailingExpansion)
-        expandRight = false;
-    if (forceLeadingExpansion)
-        expandLeft = true;
-    if (forceTrailingExpansion)
-        expandRight = true;
-    return std::make_pair(expandLeft, expandRight);
-}
-
-void ComplexTextController::adjustGlyphsAndAdvances()
-{
-    bool afterExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForbidLeadingExpansion;
-    float widthSinceLastCommit = 0;
-    size_t runCount = m_complexTextRuns.size();
-    bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled();
-    bool runForcesLeadingExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForceLeadingExpansion;
-    bool runForcesTrailingExpansion = (m_run.expansionBehavior() & TrailingExpansionMask) == ForceTrailingExpansion;
-    bool runForbidsLeadingExpansion = (m_run.expansionBehavior() & LeadingExpansionMask) == ForbidLeadingExpansion;
-    bool runForbidsTrailingExpansion = (m_run.expansionBehavior() & TrailingExpansionMask) == ForbidTrailingExpansion;
-
-    // We are iterating in glyph order, not string order. Compare this to WidthIterator::advanceInternal()
-    for (size_t runIndex = 0; runIndex < runCount; ++runIndex) {
-        ComplexTextRun& complexTextRun = *m_complexTextRuns[runIndex];
-        unsigned glyphCount = complexTextRun.glyphCount();
-        const Font& font = complexTextRun.font();
-
-        if (!complexTextRun.isLTR())
-            m_isLTROnly = false;
-
-        const CGGlyph* glyphs = complexTextRun.glyphs();
-        const FloatSize* advances = complexTextRun.baseAdvances();
-
-        bool lastRun = runIndex + 1 == runCount;
-        float spaceWidth = font.spaceWidth() - font.syntheticBoldOffset();
-        const UChar* cp = complexTextRun.characters();
-        FloatPoint glyphOrigin;
-        unsigned lastCharacterIndex = m_run.ltr() ? std::numeric_limits<unsigned>::min() : std::numeric_limits<unsigned>::max();
-        bool isMonotonic = true;
-
-        for (unsigned i = 0; i < glyphCount; i++) {
-            unsigned characterIndex = complexTextRun.indexAt(i);
-            if (m_run.ltr()) {
-                if (characterIndex < lastCharacterIndex)
-                    isMonotonic = false;
-            } else {
-                if (characterIndex > lastCharacterIndex)
-                    isMonotonic = false;
-            }
-            UChar ch = *(cp + characterIndex);
-            bool lastGlyph = lastRun && i + 1 == glyphCount;
-            UChar nextCh;
-            if (lastGlyph)
-                nextCh = ' ';
-            else if (i + 1 < glyphCount)
-                nextCh = *(cp + complexTextRun.indexAt(i + 1));
-            else
-                nextCh = *(m_complexTextRuns[runIndex + 1]->characters() + m_complexTextRuns[runIndex + 1]->indexAt(0));
-
-            bool treatAsSpace = FontCascade::treatAsSpace(ch);
-            CGGlyph glyph = treatAsSpace ? font.spaceGlyph() : glyphs[i];
-            FloatSize advance = treatAsSpace ? FloatSize(spaceWidth, advances[i].height()) : advances[i];
-
-            if (ch == '\t' && m_run.allowTabs())
-                advance.setWidth(m_font.tabWidth(font, m_run.tabSize(), m_run.xPos() + m_totalWidth + widthSinceLastCommit));
-            else if (FontCascade::treatAsZeroWidthSpace(ch) && !treatAsSpace) {
-                advance.setWidth(0);
-                glyph = font.spaceGlyph();
-            }
-
-            if (!i) {
-                advance.expand(complexTextRun.initialAdvance().width(), complexTextRun.initialAdvance().height());
-                if (auto* origins = complexTextRun.glyphOrigins())
-                    advance.expand(-origins[0].x(), -origins[0].y());
-            }
-
-            advance.expand(font.syntheticBoldOffset(), 0);
-
-            if (hasExtraSpacing) {
-                // If we're a glyph with an advance, add in letter-spacing.
-                // That way we weed out zero width lurkers. This behavior matches the fast text code path.
-                if (advance.width())
-                    advance.expand(m_font.letterSpacing(), 0);
-
-                unsigned characterIndexInRun = characterIndex + complexTextRun.stringLocation();
-                bool isFirstCharacter = !(characterIndex + complexTextRun.stringLocation());
-                bool isLastCharacter = characterIndexInRun + 1 == m_run.length() || (U16_IS_LEAD(ch) && characterIndexInRun + 2 == m_run.length() && U16_IS_TRAIL(*(cp + characterIndex + 1)));
-
-                bool forceLeadingExpansion = false; // On the left, regardless of m_run.ltr()
-                bool forceTrailingExpansion = false; // On the right, regardless of m_run.ltr()
-                bool forbidLeadingExpansion = false;
-                bool forbidTrailingExpansion = false;
-                if (runForcesLeadingExpansion)
-                    forceLeadingExpansion = m_run.ltr() ? isFirstCharacter : isLastCharacter;
-                if (runForcesTrailingExpansion)
-                    forceTrailingExpansion = m_run.ltr() ? isLastCharacter : isFirstCharacter;
-                if (runForbidsLeadingExpansion)
-                    forbidLeadingExpansion = m_run.ltr() ? isFirstCharacter : isLastCharacter;
-                if (runForbidsTrailingExpansion)
-                    forbidTrailingExpansion = m_run.ltr() ? isLastCharacter : isFirstCharacter;
-                // Handle justification and word-spacing.
-                bool ideograph = FontCascade::isCJKIdeographOrSymbol(ch);
-                if (treatAsSpace || ideograph || forceLeadingExpansion || forceTrailingExpansion) {
-                    // Distribute the run's total expansion evenly over all expansion opportunities in the run.
-                    if (m_expansion) {
-                        bool expandLeft, expandRight;
-                        std::tie(expandLeft, expandRight) = expansionLocation(ideograph, treatAsSpace, m_run.ltr(), afterExpansion, forbidLeadingExpansion, forbidTrailingExpansion, forceLeadingExpansion, forceTrailingExpansion);
-                        m_expansion -= m_expansionPerOpportunity;
-                        advance.expand(m_expansionPerOpportunity, 0);
-                        if (expandLeft) {
-                            // Increase previous width
-                            if (m_adjustedBaseAdvances.isEmpty())
-                                complexTextRun.growInitialAdvanceHorizontally(m_expansionPerOpportunity);
-                            else
-                                m_adjustedBaseAdvances.last().expand(m_expansionPerOpportunity, 0);
-                        }
-                        if (expandRight)
-                            afterExpansion = true;
-                    } else
-                        afterExpansion = false;
-
-                    // Account for word-spacing.
-                    if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || runIndex > 0) && m_font.wordSpacing())
-                        advance.expand(m_font.wordSpacing(), 0);
-                } else
-                    afterExpansion = false;
-            }
-
-            widthSinceLastCommit += advance.width();
-
-            // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space.
-            if (m_forTextEmphasis && (!FontCascade::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK)))
-                glyph = 0;
-
-            m_adjustedBaseAdvances.append(advance);
-            if (auto* origins = complexTextRun.glyphOrigins()) {
-                ASSERT(m_glyphOrigins.size() < m_adjustedBaseAdvances.size());
-                m_glyphOrigins.grow(m_adjustedBaseAdvances.size());
-                m_glyphOrigins[m_glyphOrigins.size() - 1] = origins[i];
-                ASSERT(m_glyphOrigins.size() == m_adjustedBaseAdvances.size());
-            }
-            m_adjustedGlyphs.append(glyph);
-            
-            FloatRect glyphBounds = font.boundsForGlyph(glyph);
-            glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
-            m_minGlyphBoundingBoxX = std::min(m_minGlyphBoundingBoxX, glyphBounds.x());
-            m_maxGlyphBoundingBoxX = std::max(m_maxGlyphBoundingBoxX, glyphBounds.maxX());
-            m_minGlyphBoundingBoxY = std::min(m_minGlyphBoundingBoxY, glyphBounds.y());
-            m_maxGlyphBoundingBoxY = std::max(m_maxGlyphBoundingBoxY, glyphBounds.maxY());
-            glyphOrigin.move(advance);
-            
-            lastCharacterIndex = characterIndex;
-        }
-        if (!isMonotonic)
-            complexTextRun.setIsNonMonotonic();
-    }
-
-    m_totalWidth += widthSinceLastCommit;
-}
-
-} // namespace WebCore

Deleted: trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h (211775 => 211776)


--- trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h	2017-02-07 06:45:43 UTC (rev 211775)
+++ trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h	2017-02-07 08:14:06 UTC (rev 211776)
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "FloatPoint.h"
-#include "GlyphBuffer.h"
-#include <wtf/HashSet.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RetainPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
-
-#define USE_LAYOUT_SPECIFIC_ADVANCES ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000))
-
-typedef unsigned short CGGlyph;
-
-typedef const struct __CTRun * CTRunRef;
-typedef const struct __CTLine * CTLineRef;
-
-namespace WebCore {
-
-class FontCascade;
-class Font;
-class TextRun;
-
-enum GlyphIterationStyle { IncludePartialGlyphs, ByWholeGlyphs };
-
-// See https://trac.webkit.org/wiki/ComplexTextController for more information about ComplexTextController.
-class ComplexTextController {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    ComplexTextController(const FontCascade&, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const Font*>* fallbackFonts = 0, bool forTextEmphasis = false);
-
-    class ComplexTextRun;
-    WEBCORE_EXPORT ComplexTextController(const FontCascade&, const TextRun&, Vector<Ref<ComplexTextRun>>&);
-
-    // Advance and emit glyphs up to the specified character.
-    WEBCORE_EXPORT void advance(unsigned to, GlyphBuffer* = nullptr, GlyphIterationStyle = IncludePartialGlyphs, HashSet<const Font*>* fallbackFonts = nullptr);
-
-    // Compute the character offset for a given x coordinate.
-    unsigned offsetForPosition(float x, bool includePartialGlyphs);
-
-    // Returns the width of everything we've consumed so far.
-    float runWidthSoFar() const { return m_runWidthSoFar; }
-
-    float totalWidth() const { return m_totalWidth; }
-
-    float minGlyphBoundingBoxX() const { return m_minGlyphBoundingBoxX; }
-    float maxGlyphBoundingBoxX() const { return m_maxGlyphBoundingBoxX; }
-    float minGlyphBoundingBoxY() const { return m_minGlyphBoundingBoxY; }
-    float maxGlyphBoundingBoxY() const { return m_maxGlyphBoundingBoxY; }
-
-    class ComplexTextRun : public RefCounted<ComplexTextRun> {
-    public:
-        static Ref<ComplexTextRun> create(CTRunRef ctRun, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd)
-        {
-            return adoptRef(*new ComplexTextRun(ctRun, font, characters, stringLocation, stringLength, indexBegin, indexEnd));
-        }
-
-        static Ref<ComplexTextRun> create(const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr)
-        {
-            return adoptRef(*new ComplexTextRun(font, characters, stringLocation, stringLength, indexBegin, indexEnd, ltr));
-        }
-
-        static Ref<ComplexTextRun> create(const Vector<FloatSize>& advances, const Vector<FloatPoint>& origins, const Vector<Glyph>& glyphs, const Vector<unsigned>& stringIndices, FloatSize initialAdvance, const Font& font, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr)
-        {
-            return adoptRef(*new ComplexTextRun(advances, origins, glyphs, stringIndices, initialAdvance, font, characters, stringLocation, stringLength, indexBegin, indexEnd, ltr));
-        }
-
-        unsigned glyphCount() const { return m_glyphCount; }
-        const Font& font() const { return m_font; }
-        const UChar* characters() const { return m_characters; }
-        unsigned stringLocation() const { return m_stringLocation; }
-        unsigned stringLength() const { return m_stringLength; }
-        ALWAYS_INLINE unsigned indexAt(unsigned) const;
-        unsigned indexBegin() const { return m_indexBegin; }
-        unsigned indexEnd() const { return m_indexEnd; }
-        unsigned endOffsetAt(unsigned i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; }
-        const CGGlyph* glyphs() const { return m_glyphs.data(); }
-
-        /*
-         * This is the format of the information CoreText gives us about each run:
-         *
-         *                                        ----->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):
-         *
-         *                                        ----->X------------------------->X------------------------->X
-         *                                       /            (Paint advance)            (Paint advance)       \
-         *                                      /                                                               \
-         *                   (Initial advance) /                                                                 \ (Paint advance)
-         *                  -------------------                                                                   ----------------
-         *                 /                                                                                                      \
-         *                X--------------------------------------------------X--------------------------X--------------------------X
-         * (text position ^)                (layout advance)                       (layout advance)           (layout advance)
-         */
-        void growInitialAdvanceHorizontally(float delta) { m_initialAdvance.expand(delta, 0); }
-        FloatSize initialAdvance() const { return m_initialAdvance; }
-        const FloatSize* baseAdvances() const { return m_baseAdvances.data(); }
-        const FloatPoint* glyphOrigins() const { return m_glyphOrigins.size() == glyphCount() ? m_glyphOrigins.data() : nullptr; }
-        bool isLTR() const { return m_isLTR; }
-        bool isMonotonic() const { return m_isMonotonic; }
-        void setIsNonMonotonic();
-
-    private:
-        ComplexTextRun(CTRunRef, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd);
-        ComplexTextRun(const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr);
-        WEBCORE_EXPORT ComplexTextRun(const Vector<FloatSize>& advances, const Vector<FloatPoint>& origins, const Vector<Glyph>& glyphs, const Vector<unsigned>& stringIndices, FloatSize initialAdvance, const Font&, const UChar* characters, unsigned stringLocation, unsigned stringLength, unsigned indexBegin, unsigned indexEnd, bool ltr);
-
-        Vector<FloatSize, 64> m_baseAdvances;
-        Vector<FloatPoint, 64> m_glyphOrigins;
-        Vector<CGGlyph, 64> m_glyphs;
-        Vector<unsigned, 64> m_glyphEndOffsets;
-        Vector<unsigned, 64> m_coreTextIndices;
-        FloatSize m_initialAdvance;
-        const Font& m_font;
-        const UChar* m_characters;
-        unsigned m_stringLength;
-        unsigned m_indexBegin;
-        unsigned m_indexEnd;
-        unsigned m_glyphCount;
-        unsigned m_stringLocation;
-        bool m_isLTR;
-        bool m_isMonotonic { true };
-    };
-private:
-    void computeExpansionOpportunity();
-    void finishConstruction();
-    
-    static unsigned stringBegin(const ComplexTextRun& run) { return run.stringLocation() + run.indexBegin(); }
-    static unsigned stringEnd(const ComplexTextRun& run) { return run.stringLocation() + run.indexEnd(); }
-
-    void collectComplexTextRuns();
-
-    void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const Font*);
-    void adjustGlyphsAndAdvances();
-
-    unsigned indexOfCurrentRun(unsigned& leftmostGlyph);
-    unsigned incrementCurrentRun(unsigned& leftmostGlyph);
-
-    float runWidthSoFarFraction(unsigned glyphStartOffset, unsigned glyphEndOffset, unsigned oldCharacterInCurrentGlyph, GlyphIterationStyle) const;
-
-    FloatPoint glyphOrigin(unsigned index) const { return index < m_glyphOrigins.size() ? m_glyphOrigins[index] : FloatPoint(); }
-
-    Vector<FloatSize, 256> m_adjustedBaseAdvances;
-    Vector<FloatPoint, 256> m_glyphOrigins;
-    Vector<CGGlyph, 256> m_adjustedGlyphs;
-
-    Vector<UChar, 256> m_smallCapsBuffer;
-
-    // There is a 3-level hierarchy here. At the top, we are interested in m_run.string(). We partition that string
-    // into Lines, each of which is a sequence of characters which should use the same Font. Core Text then partitions
-    // the Line into ComplexTextRuns.
-    // ComplexTextRun::stringLocation() and ComplexTextRun::stringLength() refer to the offset and length of the Line
-    // relative to m_run.string(). ComplexTextRun::indexAt() returns to the offset of a codepoint relative to
-    // its Line. ComplexTextRun::glyphs() and ComplexTextRun::advances() refer to glyphs relative to the ComplexTextRun.
-    // The length of the entire TextRun is m_run.length()
-    Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
-
-    // The initial capacity of these vectors was selected as being the smallest power of two greater than
-    // the average (3.5) plus one standard deviation (7.5) of nonzero sizes used on Arabic Wikipedia.
-    Vector<unsigned, 16> m_runIndices;
-    Vector<unsigned, 16> m_glyphCountFromStartToIndex;
-
-    Vector<RetainPtr<CTLineRef>> m_coreTextLines;
-
-    Vector<String> m_stringsFor8BitRuns;
-
-    HashSet<const Font*>* m_fallbackFonts { nullptr };
-
-    const FontCascade& m_font;
-    const TextRun& m_run;
-
-    unsigned m_currentCharacter { 0 };
-    unsigned m_end { 0 };
-
-    float m_totalWidth { 0 };
-    float m_runWidthSoFar { 0 };
-    unsigned m_numGlyphsSoFar { 0 };
-    unsigned m_currentRun { 0 };
-    unsigned m_glyphInCurrentRun { 0 };
-    unsigned m_characterInCurrentGlyph { 0 };
-    float m_expansion { 0 };
-    float m_expansionPerOpportunity { 0 };
-
-    float m_minGlyphBoundingBoxX { std::numeric_limits<float>::max() };
-    float m_maxGlyphBoundingBoxX { std::numeric_limits<float>::min() };
-    float m_minGlyphBoundingBoxY { std::numeric_limits<float>::max() };
-    float m_maxGlyphBoundingBoxY { std::numeric_limits<float>::min() };
-
-    bool m_isLTROnly { true };
-    bool m_mayUseNaturalWritingDirection { false };
-    bool m_forTextEmphasis { false };
-};
-
-} // namespace WebCore
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to