Title: [234000] trunk/Source/WebCore
Revision
234000
Author
[email protected]
Date
2018-07-19 13:36:13 -0700 (Thu, 19 Jul 2018)

Log Message

[LFC] Introduce simple line breaker.
https://bugs.webkit.org/show_bug.cgi?id=187688

Reviewed by Antti Koivisto.

This patch takes the simple line layout implementation and refactors it in a way it is no longer requires a RenderBlockFlow object to run on.
Also this patch decouples text run generation and line breaking (and this implementation is going to replace the current simple line layout codebase)

TextContentProvider: Acts both as the container for all the text content (including hard line breaks) and as an iterator for the generated text runs.
SimpleTextRunGenerator: TextContentProvider uses it as the text run generator for simple content (in the future we'll have a ComplexTextRunGenerator).
SimpleLineBreaker: Input -> text runs + line constraints; Output -> layout runs after line breaking.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/inlineformatting/textlayout/ContentProvider.cpp: Added.
(WebCore::Layout::TextContentProvider::TextItem::Style::Style):
(WebCore::Layout::TextContentProvider::ContentProvider):
(WebCore::Layout::TextContentProvider::~ContentProvider):
(WebCore::Layout::TextContentProvider::appendText):
(WebCore::Layout::TextContentProvider::appendLineBreak):
(WebCore::Layout::TextContentProvider::width const):
(WebCore::Layout::TextContentProvider::textWidth const):
(WebCore::Layout::TextContentProvider::fixedPitchWidth const):
(WebCore::Layout::TextContentProvider::toTextItemIndex const):
(WebCore::Layout::TextContentProvider::length const):
(WebCore::Layout::TextContentProvider::iterator):
(WebCore::Layout::TextContentProvider::findNextRun):
(WebCore::Layout::TextContentProvider::current const):
* layout/inlineformatting/textlayout/ContentProvider.h: Added.
(WebCore::Layout::TextContentProvider::textContent const):
(WebCore::Layout::TextContentProvider::hardLineBreaks const):
(WebCore::Layout::TextContentProvider::Iterator::current const):
(WebCore::Layout::TextContentProvider::contains const):
(WebCore::Layout::TextContentProvider::Iterator::Iterator):
(WebCore::Layout::TextContentProvider::Iterator::operator++):
* layout/inlineformatting/textlayout/Runs.h: Added.
(WebCore::Layout::TextRun::isWhitespace const):
(WebCore::Layout::TextRun::isNonWhitespace const):
(WebCore::Layout::TextRun::isLineBreak const):
(WebCore::Layout::TextRun::isSoftLineBreak const):
(WebCore::Layout::TextRun::isHardLineBreak const):
(WebCore::Layout::TextRun::isValid const):
(WebCore::Layout::TextRun::isCollapsed const):
(WebCore::Layout::TextRun::type const):
(WebCore::Layout::TextRun::setIsCollapsed):
(WebCore::Layout::TextRun::setWidth):
(WebCore::Layout::LayoutRun::start const):
(WebCore::Layout::LayoutRun::end const):
(WebCore::Layout::LayoutRun::length const):
(WebCore::Layout::LayoutRun::left const):
(WebCore::Layout::LayoutRun::right const):
(WebCore::Layout::LayoutRun::width const):
(WebCore::Layout::LayoutRun::isEndOfLine const):
(WebCore::Layout::LayoutRun::setEnd):
(WebCore::Layout::LayoutRun::setRight):
(WebCore::Layout::LayoutRun::setIsEndOfLine):
(WebCore::Layout::LayoutRun::LayoutRun):
(WebCore::Layout::TextRun::createWhitespaceRun):
(WebCore::Layout::TextRun::createNonWhitespaceRun):
(WebCore::Layout::TextRun::createSoftLineBreakRun):
(WebCore::Layout::TextRun::createHardLineBreakRun):
(WebCore::Layout::TextRun::TextRun):
(WebCore::Layout::TextRun::start const):
(WebCore::Layout::TextRun::end const):
(WebCore::Layout::TextRun::length const):
(WebCore::Layout::TextRun::width const):
* layout/inlineformatting/textlayout/simple/SimpleContentProvider.cpp: Added.
(WebCore::Layout::SimpleContentProvider::SimpleContentProvider):
(WebCore::Layout::SimpleContentProvider::current const):
(WebCore::Layout::SimpleContentProvider::reset):
(WebCore::Layout::SimpleContentProvider::findNextRun):
(WebCore::Layout::SimpleContentProvider::moveToNextBreakablePosition):
(WebCore::Layout::SimpleContentProvider::moveToNextNonWhitespacePosition):
(WebCore::Layout::SimpleContentProvider::isAtLineBreak const):
(WebCore::Layout::SimpleContentProvider::isAtSoftLineBreak const):
* layout/inlineformatting/textlayout/simple/SimpleContentProvider.h: Added.
(WebCore::Layout::SimpleContentProvider::Iterator::reset):
(WebCore::Layout::SimpleContentProvider::Position::operator== const):
(WebCore::Layout::SimpleContentProvider::Position::operator< const):
(WebCore::Layout::SimpleContentProvider::Position::operator ContentPosition const):
(WebCore::Layout::SimpleContentProvider::Position::resetItemPosition):
(WebCore::Layout::SimpleContentProvider::Position::contentPosition const):
(WebCore::Layout::SimpleContentProvider::Position::itemPosition const):
(WebCore::Layout::SimpleContentProvider::Iterator<T>::Iterator):
(WebCore::Layout::SimpleContentProvider::Iterator<T>::current const):
(WebCore::Layout::SimpleContentProvider::Iterator<T>::operator):
(WebCore::Layout::SimpleContentProvider::Position::operator++):
(WebCore::Layout::SimpleContentProvider::Position::operator+=):
* layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp: Added.
(WebCore::Layout::SimpleLineBreaker::TextRunList::TextRunList):
(WebCore::Layout::SimpleLineBreaker::Line::Line):
(WebCore::Layout::adjustedEndPosition):
(WebCore::Layout::SimpleLineBreaker::Line::append):
(WebCore::Layout::SimpleLineBreaker::Line::collapseTrailingWhitespace):
(WebCore::Layout::SimpleLineBreaker::Line::reset):
(WebCore::Layout::SimpleLineBreaker::Style::Style):
(WebCore::Layout::SimpleLineBreaker::SimpleLineBreaker):
(WebCore::Layout::SimpleLineBreaker::runs):
(WebCore::Layout::SimpleLineBreaker::createRunsForLine):
(WebCore::Layout::SimpleLineBreaker::handleOverflownRun):
(WebCore::Layout::SimpleLineBreaker::collapseLeadingWhitespace):
(WebCore::Layout::SimpleLineBreaker::collapseTrailingWhitespace):
(WebCore::Layout::SimpleLineBreaker::splitTextRun):
(WebCore::Layout::SimpleLineBreaker::split const):
(WebCore::Layout::SimpleLineBreaker::availableWidth const):
(WebCore::Layout::SimpleLineBreaker::verticalPosition const):
* layout/inlineformatting/textlayout/simple/SimpleLineBreaker.h: Added.
(WebCore::Layout::SimpleLineBreaker::TextRunList::overrideCurrent):
(WebCore::Layout::SimpleLineBreaker::TextRunList::isCurrentOverridden const):
(WebCore::Layout::SimpleLineBreaker::Line::availableWidth const):
(WebCore::Layout::SimpleLineBreaker::Line::hasContent const):
(WebCore::Layout::SimpleLineBreaker::Line::setAvailableWidth):
(WebCore::Layout::SimpleLineBreaker::Line::hasTrailingWhitespace const):
(WebCore::Layout::SimpleLineBreaker::Line::isWhitespaceOnly const):
(WebCore::Layout::SimpleLineBreaker::wrapContentOnOverflow const):
(WebCore::Layout::SimpleLineBreaker::TextRunList::current const):
(WebCore::Layout::SimpleLineBreaker::TextRunList::operator++):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (233999 => 234000)


--- trunk/Source/WebCore/ChangeLog	2018-07-19 19:43:00 UTC (rev 233999)
+++ trunk/Source/WebCore/ChangeLog	2018-07-19 20:36:13 UTC (rev 234000)
@@ -1,3 +1,123 @@
+2018-07-19  Zalan Bujtas  <[email protected]>
+
+        [LFC] Introduce simple line breaker.
+        https://bugs.webkit.org/show_bug.cgi?id=187688
+
+        Reviewed by Antti Koivisto.
+
+        This patch takes the simple line layout implementation and refactors it in a way it is no longer requires a RenderBlockFlow object to run on.
+        Also this patch decouples text run generation and line breaking (and this implementation is going to replace the current simple line layout codebase)
+
+        TextContentProvider: Acts both as the container for all the text content (including hard line breaks) and as an iterator for the generated text runs.
+        SimpleTextRunGenerator: TextContentProvider uses it as the text run generator for simple content (in the future we'll have a ComplexTextRunGenerator).
+        SimpleLineBreaker: Input -> text runs + line constraints; Output -> layout runs after line breaking.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/inlineformatting/textlayout/ContentProvider.cpp: Added.
+        (WebCore::Layout::TextContentProvider::TextItem::Style::Style):
+        (WebCore::Layout::TextContentProvider::ContentProvider):
+        (WebCore::Layout::TextContentProvider::~ContentProvider):
+        (WebCore::Layout::TextContentProvider::appendText):
+        (WebCore::Layout::TextContentProvider::appendLineBreak):
+        (WebCore::Layout::TextContentProvider::width const):
+        (WebCore::Layout::TextContentProvider::textWidth const):
+        (WebCore::Layout::TextContentProvider::fixedPitchWidth const):
+        (WebCore::Layout::TextContentProvider::toTextItemIndex const):
+        (WebCore::Layout::TextContentProvider::length const):
+        (WebCore::Layout::TextContentProvider::iterator):
+        (WebCore::Layout::TextContentProvider::findNextRun):
+        (WebCore::Layout::TextContentProvider::current const):
+        * layout/inlineformatting/textlayout/ContentProvider.h: Added.
+        (WebCore::Layout::TextContentProvider::textContent const):
+        (WebCore::Layout::TextContentProvider::hardLineBreaks const):
+        (WebCore::Layout::TextContentProvider::Iterator::current const):
+        (WebCore::Layout::TextContentProvider::contains const):
+        (WebCore::Layout::TextContentProvider::Iterator::Iterator):
+        (WebCore::Layout::TextContentProvider::Iterator::operator++):
+        * layout/inlineformatting/textlayout/Runs.h: Added.
+        (WebCore::Layout::TextRun::isWhitespace const):
+        (WebCore::Layout::TextRun::isNonWhitespace const):
+        (WebCore::Layout::TextRun::isLineBreak const):
+        (WebCore::Layout::TextRun::isSoftLineBreak const):
+        (WebCore::Layout::TextRun::isHardLineBreak const):
+        (WebCore::Layout::TextRun::isValid const):
+        (WebCore::Layout::TextRun::isCollapsed const):
+        (WebCore::Layout::TextRun::type const):
+        (WebCore::Layout::TextRun::setIsCollapsed):
+        (WebCore::Layout::TextRun::setWidth):
+        (WebCore::Layout::LayoutRun::start const):
+        (WebCore::Layout::LayoutRun::end const):
+        (WebCore::Layout::LayoutRun::length const):
+        (WebCore::Layout::LayoutRun::left const):
+        (WebCore::Layout::LayoutRun::right const):
+        (WebCore::Layout::LayoutRun::width const):
+        (WebCore::Layout::LayoutRun::isEndOfLine const):
+        (WebCore::Layout::LayoutRun::setEnd):
+        (WebCore::Layout::LayoutRun::setRight):
+        (WebCore::Layout::LayoutRun::setIsEndOfLine):
+        (WebCore::Layout::LayoutRun::LayoutRun):
+        (WebCore::Layout::TextRun::createWhitespaceRun):
+        (WebCore::Layout::TextRun::createNonWhitespaceRun):
+        (WebCore::Layout::TextRun::createSoftLineBreakRun):
+        (WebCore::Layout::TextRun::createHardLineBreakRun):
+        (WebCore::Layout::TextRun::TextRun):
+        (WebCore::Layout::TextRun::start const):
+        (WebCore::Layout::TextRun::end const):
+        (WebCore::Layout::TextRun::length const):
+        (WebCore::Layout::TextRun::width const):
+        * layout/inlineformatting/textlayout/simple/SimpleContentProvider.cpp: Added.
+        (WebCore::Layout::SimpleContentProvider::SimpleContentProvider):
+        (WebCore::Layout::SimpleContentProvider::current const):
+        (WebCore::Layout::SimpleContentProvider::reset):
+        (WebCore::Layout::SimpleContentProvider::findNextRun):
+        (WebCore::Layout::SimpleContentProvider::moveToNextBreakablePosition):
+        (WebCore::Layout::SimpleContentProvider::moveToNextNonWhitespacePosition):
+        (WebCore::Layout::SimpleContentProvider::isAtLineBreak const):
+        (WebCore::Layout::SimpleContentProvider::isAtSoftLineBreak const):
+        * layout/inlineformatting/textlayout/simple/SimpleContentProvider.h: Added.
+        (WebCore::Layout::SimpleContentProvider::Iterator::reset):
+        (WebCore::Layout::SimpleContentProvider::Position::operator== const):
+        (WebCore::Layout::SimpleContentProvider::Position::operator< const):
+        (WebCore::Layout::SimpleContentProvider::Position::operator ContentPosition const):
+        (WebCore::Layout::SimpleContentProvider::Position::resetItemPosition):
+        (WebCore::Layout::SimpleContentProvider::Position::contentPosition const):
+        (WebCore::Layout::SimpleContentProvider::Position::itemPosition const):
+        (WebCore::Layout::SimpleContentProvider::Iterator<T>::Iterator):
+        (WebCore::Layout::SimpleContentProvider::Iterator<T>::current const):
+        (WebCore::Layout::SimpleContentProvider::Iterator<T>::operator):
+        (WebCore::Layout::SimpleContentProvider::Position::operator++):
+        (WebCore::Layout::SimpleContentProvider::Position::operator+=):
+        * layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp: Added.
+        (WebCore::Layout::SimpleLineBreaker::TextRunList::TextRunList):
+        (WebCore::Layout::SimpleLineBreaker::Line::Line):
+        (WebCore::Layout::adjustedEndPosition):
+        (WebCore::Layout::SimpleLineBreaker::Line::append):
+        (WebCore::Layout::SimpleLineBreaker::Line::collapseTrailingWhitespace):
+        (WebCore::Layout::SimpleLineBreaker::Line::reset):
+        (WebCore::Layout::SimpleLineBreaker::Style::Style):
+        (WebCore::Layout::SimpleLineBreaker::SimpleLineBreaker):
+        (WebCore::Layout::SimpleLineBreaker::runs):
+        (WebCore::Layout::SimpleLineBreaker::createRunsForLine):
+        (WebCore::Layout::SimpleLineBreaker::handleOverflownRun):
+        (WebCore::Layout::SimpleLineBreaker::collapseLeadingWhitespace):
+        (WebCore::Layout::SimpleLineBreaker::collapseTrailingWhitespace):
+        (WebCore::Layout::SimpleLineBreaker::splitTextRun):
+        (WebCore::Layout::SimpleLineBreaker::split const):
+        (WebCore::Layout::SimpleLineBreaker::availableWidth const):
+        (WebCore::Layout::SimpleLineBreaker::verticalPosition const):
+        * layout/inlineformatting/textlayout/simple/SimpleLineBreaker.h: Added.
+        (WebCore::Layout::SimpleLineBreaker::TextRunList::overrideCurrent):
+        (WebCore::Layout::SimpleLineBreaker::TextRunList::isCurrentOverridden const):
+        (WebCore::Layout::SimpleLineBreaker::Line::availableWidth const):
+        (WebCore::Layout::SimpleLineBreaker::Line::hasContent const):
+        (WebCore::Layout::SimpleLineBreaker::Line::setAvailableWidth):
+        (WebCore::Layout::SimpleLineBreaker::Line::hasTrailingWhitespace const):
+        (WebCore::Layout::SimpleLineBreaker::Line::isWhitespaceOnly const):
+        (WebCore::Layout::SimpleLineBreaker::wrapContentOnOverflow const):
+        (WebCore::Layout::SimpleLineBreaker::TextRunList::current const):
+        (WebCore::Layout::SimpleLineBreaker::TextRunList::operator++):
+
 2018-07-19  Keith Rollin  <[email protected]>
 
         Remove duplicate compilation of WebKitNSImageExtras.mm

Modified: trunk/Source/WebCore/Sources.txt (233999 => 234000)


--- trunk/Source/WebCore/Sources.txt	2018-07-19 19:43:00 UTC (rev 233999)
+++ trunk/Source/WebCore/Sources.txt	2018-07-19 20:36:13 UTC (rev 234000)
@@ -1232,6 +1232,9 @@
 layout/inlineformatting/InlineFormattingContext.cpp
 layout/inlineformatting/InlineFormattingState.cpp
 layout/inlineformatting/InlineInvalidation.cpp
+layout/inlineformatting/textlayout/TextContentProvider.cpp
+layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.cpp
+layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp
 layout/layouttree/LayoutBlockContainer.cpp
 layout/layouttree/LayoutBox.cpp
 layout/layouttree/LayoutContainer.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (233999 => 234000)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-07-19 19:43:00 UTC (rev 233999)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2018-07-19 20:36:13 UTC (rev 234000)
@@ -5807,6 +5807,8 @@
 		11CB2787203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderFullScreen.h; sourceTree = "<group>"; };
 		11E067EB1E62461300162D16 /* SimpleLineLayoutCoverage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutCoverage.cpp; sourceTree = "<group>"; };
 		11E067ED1E6246E500162D16 /* SimpleLineLayoutCoverage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutCoverage.h; sourceTree = "<group>"; };
+		11EA57FB20FFAFB600311EBB /* SimpleTextRunGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleTextRunGenerator.cpp; sourceTree = "<group>"; };
+		11EA57FC20FFAFB700311EBB /* SimpleTextRunGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleTextRunGenerator.h; sourceTree = "<group>"; };
 		11FF02D520BA3C810083F25B /* Verification.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Verification.cpp; sourceTree = "<group>"; };
 		1400D7A717136EA70077CE05 /* ScriptWrappableInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptWrappableInlines.h; sourceTree = "<group>"; };
 		1402645D0AFDC19B005919E2 /* LoggingMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = LoggingMac.mm; sourceTree = "<group>"; };
@@ -8916,6 +8918,8 @@
 		6F7CA3C5208C2956002F29AB /* LayoutContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutContext.cpp; sourceTree = "<group>"; };
 		6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InlineFormattingContext.h; sourceTree = "<group>"; };
 		6F7CA3C9208C2B2E002F29AB /* InlineFormattingContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InlineFormattingContext.cpp; sourceTree = "<group>"; };
+		6F8304C920FBA5E1004AD5D1 /* SimpleLineBreaker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineBreaker.cpp; sourceTree = "<group>"; };
+		6F8304CA20FBA5E1004AD5D1 /* SimpleLineBreaker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleLineBreaker.h; sourceTree = "<group>"; };
 		6F995A091A7070E600A735F4 /* WebGLQuery.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebGLQuery.idl; sourceTree = "<group>"; };
 		6F995A0A1A7070E600A735F4 /* WebGLSampler.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebGLSampler.idl; sourceTree = "<group>"; };
 		6F995A0B1A7070E600A735F4 /* WebGLSync.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebGLSync.idl; sourceTree = "<group>"; };
@@ -8942,6 +8946,9 @@
 		6F995A2F1A70833700A735F4 /* JSWebGLVertexArrayObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLVertexArrayObject.cpp; sourceTree = "<group>"; };
 		6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLVertexArrayObject.h; sourceTree = "<group>"; };
 		6FBB860520B464B600DAD938 /* FormattingContextGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FormattingContextGeometry.cpp; sourceTree = "<group>"; };
+		6FCD19C120F9727A00FD4529 /* TextContentProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextContentProvider.h; sourceTree = "<group>"; };
+		6FCD19C720F9727D00FD4529 /* TextContentProvider.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TextContentProvider.cpp; sourceTree = "<group>"; };
+		6FCF975220F02B3500214960 /* Runs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Runs.h; sourceTree = "<group>"; };
 		709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleFetchFailureKind.h; sourceTree = "<group>"; };
 		71004B9D1DC1398800A52A38 /* playback-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "playback-support.js"; sourceTree = "<group>"; };
 		71025EC21F99F096004A250C /* WebAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAnimation.h; sourceTree = "<group>"; };
@@ -15775,6 +15782,7 @@
 		115CFA9A208BC140001E6991 /* inlineformatting */ = {
 			isa = PBXGroup;
 			children = (
+				6FE7DDDD20EC6E8B008B5B4E /* textlayout */,
 				6F7CA3C9208C2B2E002F29AB /* InlineFormattingContext.cpp */,
 				6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */,
 				115CFA7D208B8E10001E6991 /* InlineFormattingState.cpp */,
@@ -19501,6 +19509,28 @@
 			tabWidth = 4;
 			usesTabs = 0;
 		};
+		6F13A12320F9949C001C025A /* simple */ = {
+			isa = PBXGroup;
+			children = (
+				6F8304C920FBA5E1004AD5D1 /* SimpleLineBreaker.cpp */,
+				6F8304CA20FBA5E1004AD5D1 /* SimpleLineBreaker.h */,
+				11EA57FB20FFAFB600311EBB /* SimpleTextRunGenerator.cpp */,
+				11EA57FC20FFAFB700311EBB /* SimpleTextRunGenerator.h */,
+			);
+			path = simple;
+			sourceTree = "<group>";
+		};
+		6FE7DDDD20EC6E8B008B5B4E /* textlayout */ = {
+			isa = PBXGroup;
+			children = (
+				6F13A12320F9949C001C025A /* simple */,
+				6FCF975220F02B3500214960 /* Runs.h */,
+				6FCD19C720F9727D00FD4529 /* TextContentProvider.cpp */,
+				6FCD19C120F9727A00FD4529 /* TextContentProvider.h */,
+			);
+			path = textlayout;
+			sourceTree = "<group>";
+		};
 		71025EC11F99F096004A250C /* animation */ = {
 			isa = PBXGroup;
 			children = (

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/Runs.h (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/Runs.h	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/Runs.h	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 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
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+namespace WebCore {
+namespace Layout {
+
+using ContentPosition = unsigned;
+using ItemPosition = unsigned;
+
+struct TextRun {
+public:
+    enum class Type {
+        Whitespace,
+        NonWhitespace,
+        SoftLineBreak,
+        HardLineBreak,
+        Invalid
+    };
+    static TextRun createWhitespaceRun(ContentPosition start, ContentPosition end, float width, bool isCollapsed);
+    static TextRun createNonWhitespaceRun(ContentPosition start, ContentPosition end, float width);
+    static TextRun createSoftLineBreakRun(ContentPosition);
+    static TextRun createHardLineBreakRun(ContentPosition);
+
+    TextRun() = default;
+    TextRun(ContentPosition start, ContentPosition end, Type, float width = 0, bool isCollapsed = false);
+
+    ContentPosition start() const;
+    ContentPosition end() const;
+    unsigned length() const;
+
+    float width() const;
+
+    bool isWhitespace() const { return m_type == Type::Whitespace; }
+    bool isNonWhitespace() const { return m_type == Type::NonWhitespace; }
+    bool isLineBreak() const { return isSoftLineBreak() || isHardLineBreak(); }
+    bool isSoftLineBreak() const { return m_type == Type::SoftLineBreak; }
+    bool isHardLineBreak() const { return m_type == Type::HardLineBreak; }
+    bool isValid() const { return m_type != Type::Invalid; }
+    bool isCollapsed() const { return m_isCollapsed; }
+    Type type() const { return m_type; }
+
+    void setIsCollapsed(bool isCollapsed) { m_isCollapsed = isCollapsed; }
+    void setWidth(float width) { m_width = width; }
+
+private:
+    ContentPosition m_start { 0 };
+    ContentPosition m_end { 0 };
+    Type m_type { Type::Invalid };
+    float m_width { 0 };
+    bool m_isCollapsed { false };
+};
+
+struct LayoutRun {
+public:
+    LayoutRun(ContentPosition start, ContentPosition end, float left, float right);
+
+    ContentPosition start() const { return m_start; }
+    ContentPosition end() const { return m_end; }
+    unsigned length() const { return end() - start(); }
+
+    float left() const { return m_left; }
+    float right() const { return m_right; }
+    float width() const { return right() - left(); }
+
+    bool isEndOfLine() const { return m_isEndOfLine; }
+
+    void setEnd(ContentPosition end) { m_end = end; }
+    void setRight(float right) { m_right = right; }
+    void setIsEndOfLine() { m_isEndOfLine = true; }
+
+private:
+    ContentPosition m_start { 0 };
+    ContentPosition m_end { 0 };
+    float m_left { 0 };
+    float m_right { 0 };
+    bool m_isEndOfLine { false };
+};
+
+template<typename T>
+class ConstVectorIterator {
+public:
+    ConstVectorIterator(const Vector<T>&);
+
+    const T* current() const;
+    ConstVectorIterator<T>& operator++();
+    void reset() { m_index = 0; }
+
+private:
+    const Vector<T>& m_content;
+    unsigned m_index { 0 };
+};
+
+template<typename T>
+inline ConstVectorIterator<T>::ConstVectorIterator(const Vector<T>& content)
+    : m_content(content)
+{
+}
+
+template<typename T>
+inline const T* ConstVectorIterator<T>::current() const
+{
+    if (m_index == m_content.size())
+        return nullptr;
+    return &m_content[m_index];
+}
+
+template<typename T>
+inline ConstVectorIterator<T>& ConstVectorIterator<T>::operator++()
+{
+    ++m_index;
+    return *this;
+}
+
+inline LayoutRun::LayoutRun(ContentPosition start, ContentPosition end, float left, float right)
+    : m_start(start)
+    , m_end(end)
+    , m_left(left)
+    , m_right(right)
+{
+}
+
+inline TextRun TextRun::createWhitespaceRun(ContentPosition start, ContentPosition end, float width, bool isCollapsed)
+{
+    return { start, end, Type::Whitespace, width, isCollapsed };
+}
+
+inline TextRun TextRun::createNonWhitespaceRun(ContentPosition start, ContentPosition end, float width)
+{
+    return { start, end, Type::NonWhitespace, width };
+}
+
+inline TextRun TextRun::createSoftLineBreakRun(ContentPosition position)
+{
+    return { position, position + 1, Type::SoftLineBreak };
+}
+
+inline TextRun TextRun::createHardLineBreakRun(ContentPosition position)
+{
+    return { position, position, Type::HardLineBreak };
+}
+
+inline TextRun::TextRun(ContentPosition start, ContentPosition end, Type type, float width, bool isCollapsed)
+    : m_start(start)
+    , m_end(end)
+    , m_type(type)
+    , m_width(width)
+    , m_isCollapsed(isCollapsed)
+{
+}
+
+inline ContentPosition TextRun::start() const
+{
+    ASSERT(type() != Type::Invalid);
+    return m_start;
+}
+
+inline ContentPosition TextRun::end() const
+{
+    ASSERT(type() != Type::Invalid);
+    return m_end;
+}
+
+inline unsigned TextRun::length() const
+{
+    ASSERT(type() != Type::Invalid);
+    return m_end - m_start;
+}
+
+inline float TextRun::width() const
+{
+    ASSERT(type() != Type::Invalid);
+    return m_width;
+}
+
+}
+}
+#endif

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/TextContentProvider.cpp (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/TextContentProvider.cpp	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/TextContentProvider.cpp	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2018 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 "TextContentProvider.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FontCascade.h"
+#include "RenderStyle.h"
+#include "SimpleTextRunGenerator.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(TextContentProvider);
+
+TextContentProvider::TextItem::Style::Style(const RenderStyle& style)
+    : font(style.fontCascade())
+    , collapseWhitespace(style.collapseWhiteSpace())
+    , hasKerningOrLigatures(font.enableKerning() || font.requiresShaping())
+    , wordSpacing(font.wordSpacing())
+    , tabWidth(collapseWhitespace ? 0 : style.tabSize())
+    , preserveNewline(style.preserveNewline())
+    , breakNBSP(style.autoWrap() && style.nbspMode() == NBSPMode::Space)
+    , keepAllWordsForCJK(style.wordBreak() == WordBreak::KeepAll)
+    , locale(style.locale())
+{
+}
+
+TextContentProvider::TextContentProvider()
+    : m_textContentIterator(m_textContent)
+{
+}
+
+TextContentProvider::~TextContentProvider()
+{
+}
+
+void TextContentProvider::appendText(String text, const RenderStyle& style, bool canUseSimplifiedMeasure)
+{
+    ASSERT(text.length());
+
+    auto start = length();
+    auto end = start + text.length();
+    m_textContent.append({ text, start, end, TextItem::Style(style), canUseSimplifiedMeasure });
+}
+
+void TextContentProvider::appendLineBreak()
+{
+    m_hardLineBreaks.append(length());
+}
+
+static bool contains(ContentPosition position, const TextContentProvider::TextItem& textItem)
+{
+    return textItem.start <= position && position < textItem.end;
+}
+
+float TextContentProvider::width(ContentPosition from, ContentPosition to, float xPosition) const
+{
+    auto textItemPositionSlow = [&]() -> unsigned {
+        // Since this is an iterator like class, check the next item first (instead of starting the search from the beginning).
+        if (auto* textItem = (++m_textContentIterator).current()) {
+            if (contains(from, *textItem))
+                return textItem->start;
+        }
+
+        m_textContentIterator.reset();
+        while (auto* textItem = m_textContentIterator.current()) {
+            if (contains(from, *textItem))
+                return textItem->start;
+            ++m_textContentIterator;
+        }
+
+        ASSERT_NOT_REACHED();
+        return 0;
+    };
+
+    if (from >= to) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    auto contentLength = length();
+    if (from >= contentLength || to > contentLength) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    float width = 0;
+    auto length = to - from;
+    auto* textItem = m_textContentIterator.current();
+    auto startPosition = from - (textItem && contains(from, *textItem) ? textItem->start : textItemPositionSlow());
+
+    while (length) {
+        textItem = m_textContentIterator.current();
+        if (!textItem) {
+            ASSERT_NOT_REACHED();
+            break;
+        }
+
+        auto endPosition = std::min<ItemPosition>(startPosition + length, textItem->text.length());
+        ASSERT(endPosition >= startPosition);
+        auto textWidth = this->textWidth(*textItem, startPosition, endPosition, xPosition);
+
+        xPosition += textWidth;
+        width += textWidth;
+        length -= (endPosition - startPosition);
+
+        startPosition = 0;
+        if (length)
+            ++m_textContentIterator;
+    }
+
+    return width;
+}
+
+float TextContentProvider::textWidth(const TextItem& textItem, ItemPosition from, ItemPosition to, float xPosition) const
+{
+    if (from > to || to > textItem.end - textItem.start) {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    auto& style = textItem.style;
+    auto& font = style.font;
+    if (!font.size() || from == to)
+        return 0;
+
+    if (font.isFixedPitch())
+        return fixedPitchWidth(textItem.text, style, from, to, xPosition);
+
+    auto measureWithEndSpace = style.hasKerningOrLigatures && to < textItem.text.length() && textItem.text[to] == ' ';
+    if (measureWithEndSpace)
+        ++to;
+    float width = 0;
+    if (textItem.canUseSimplifiedMeasure)
+        width = font.widthForSimpleText(StringView(textItem.text).substring(from, to - from));
+    else  {
+        WebCore::TextRun run(StringView(textItem.text).substring(from, to - from), xPosition);
+        if (style.tabWidth)
+            run.setTabSize(true, style.tabWidth);
+        width = font.width(run);
+    }
+
+    if (measureWithEndSpace)
+        width -= (font.spaceWidth() + style.wordSpacing);
+
+    return std::max<float>(0, width);
+}
+
+float TextContentProvider::fixedPitchWidth(String text, const TextItem::Style& style, ItemPosition from, ItemPosition to, float xPosition) const
+{
+    auto monospaceCharacterWidth = style.font.spaceWidth();
+    float width = 0;
+    for (auto i = from; i < to; ++i) {
+        auto character = text[i];
+        if (character >= ' ' || character == '\n')
+            width += monospaceCharacterWidth;
+        else if (character == '\t')
+            width += style.collapseWhitespace ? monospaceCharacterWidth : style.font.tabWidth(style.tabWidth, xPosition + width);
+
+        if (i > from && (character == ' ' || character == '\t' || character == '\n'))
+            width += style.font.wordSpacing();
+    }
+
+    return width;
+}
+
+unsigned TextContentProvider::length() const
+{
+    if (!m_textContent.size())
+        return 0;
+    return m_textContent.last().end;
+}
+
+TextContentProvider::Iterator TextContentProvider::iterator()
+{
+    // TODO: This is where we decide whether we need a simple or a more complex provider.
+    if (!m_simpleTextRunGenerator)
+        m_simpleTextRunGenerator = std::make_unique<SimpleTextRunGenerator>(*this);
+    else
+        m_simpleTextRunGenerator->reset();
+
+    m_simpleTextRunGenerator->findNextRun();
+    return Iterator(*this);
+}
+
+void TextContentProvider::findNextRun()
+{
+    m_simpleTextRunGenerator->findNextRun();
+}
+
+std::optional<TextRun> TextContentProvider::current() const
+{
+    return m_simpleTextRunGenerator->current();
+}
+
+}
+}
+#endif

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/TextContentProvider.h (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/TextContentProvider.h	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/TextContentProvider.h	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 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
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "Runs.h"
+#include <wtf/IsoMalloc.h>
+
+namespace WebCore {
+
+class FontCascade;
+class RenderStyle;
+
+namespace Layout {
+
+class SimpleTextRunGenerator;
+
+class TextContentProvider {
+    WTF_MAKE_ISO_ALLOCATED(TextContentProvider);
+public:
+    TextContentProvider();
+    ~TextContentProvider();
+
+    void appendText(String, const RenderStyle&, bool canUseSimplifiedMeasure);
+    void appendLineBreak();
+
+    struct TextItem {
+        struct Style {
+            explicit Style(const RenderStyle&);
+
+            const FontCascade& font;
+            bool collapseWhitespace { false };
+            bool hasKerningOrLigatures { false };
+            float wordSpacing { 0 };
+            float tabWidth { 0 };
+            bool preserveNewline { false };
+            bool breakNBSP { false };
+            bool keepAllWordsForCJK { false };
+            AtomicString locale;
+        };
+
+        const String text;
+        const ContentPosition start { 0 };
+        const ContentPosition end { 0 };
+        const Style style;
+        const bool canUseSimplifiedMeasure { false };
+    };
+    using TextContent = Vector<TextItem>;
+    const TextContent& textContent() const { return m_textContent; }
+
+    using HardLineBreaks = Vector<ContentPosition>;
+    const HardLineBreaks& hardLineBreaks() const { return m_hardLineBreaks; }
+
+    unsigned length() const;
+    float width(ContentPosition from, ContentPosition to, float xPosition) const;
+
+    class Iterator {
+    public:
+        Iterator& operator++();
+        std::optional<TextRun> current() const { return m_contentProvider.current(); };
+
+    private:
+        friend class TextContentProvider;
+        Iterator(TextContentProvider&);
+
+        TextContentProvider& m_contentProvider;
+    };
+
+    Iterator iterator();
+
+private:
+    friend class Iterator;
+
+    float textWidth(const TextItem&, ItemPosition from, ItemPosition to, float xPosition) const;
+    float fixedPitchWidth(String, const TextItem::Style&, ItemPosition from, ItemPosition to, float xPosition) const;
+
+    void findNextRun();
+    std::optional<TextRun> current() const;
+
+    TextContent m_textContent;
+    mutable ConstVectorIterator<TextItem> m_textContentIterator;
+    HardLineBreaks m_hardLineBreaks;
+    std::unique_ptr<SimpleTextRunGenerator> m_simpleTextRunGenerator;
+};
+
+inline TextContentProvider::Iterator::Iterator(TextContentProvider& contentProvider)
+    : m_contentProvider(contentProvider)
+{
+}
+
+inline TextContentProvider::Iterator& TextContentProvider::Iterator::operator++()
+{
+    m_contentProvider.findNextRun();
+    return *this;
+}
+
+}
+}
+#endif

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2018 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 "SimpleLineBreaker.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FontCascade.h"
+#include "InlineFormattingContext.h"
+#include "LayoutContext.h"
+#include "LayoutUnit.h"
+#include "RenderStyle.h"
+#include "TextContentProvider.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(SimpleLineBreaker);
+
+struct TextRunSplitPair {
+    TextRun left;
+    TextRun right;
+};
+
+SimpleLineBreaker::TextRunList::TextRunList(const Vector<TextRun>& textRuns)
+    : m_textRuns(textRuns)
+{
+}
+
+SimpleLineBreaker::Line::Line(Vector<LayoutRun>& layoutRuns)
+    : m_layoutRuns(layoutRuns)
+{
+}
+
+static inline unsigned adjustedEndPosition(const TextRun& textRun)
+{
+    if (textRun.isCollapsed())
+        return textRun.start() + 1;
+    return textRun.end();
+}
+
+void SimpleLineBreaker::Line::append(const TextRun& textRun)
+{
+    auto start = textRun.start();
+    auto end = adjustedEndPosition(textRun);
+    auto previousLogicalRight = m_left + m_runsWidth;
+
+    m_runsWidth += textRun.width();
+    if (textRun.isNonWhitespace()) {
+        m_trailingWhitespaceWidth = 0;
+        m_lastNonWhitespaceTextRun = textRun;
+    } else if (textRun.isWhitespace())
+        m_trailingWhitespaceWidth += textRun.width();
+
+    // New line needs new run.
+    if (!m_lastTextRun || m_lastTextRun->isCollapsed())
+        m_layoutRuns.append({ start, end, previousLogicalRight, previousLogicalRight + textRun.width() });
+    else {
+        auto& lastRun = m_layoutRuns.last();
+        lastRun.setEnd(end);
+        lastRun.setRight(lastRun.right() + textRun.width());
+    }
+
+    m_lastTextRun = textRun;
+}
+
+void SimpleLineBreaker::Line::collapseTrailingWhitespace()
+{
+    if (!m_lastTextRun || !m_lastTextRun->isWhitespace())
+        return;
+
+    if (!m_lastNonWhitespaceTextRun) {
+        reset();
+        return;
+    }
+
+    m_runsWidth -= m_trailingWhitespaceWidth;
+    m_lastTextRun = m_lastNonWhitespaceTextRun;
+
+    while (m_trailingWhitespaceWidth) {
+        auto& lastLayoutRun = m_layoutRuns.last();
+
+        if (lastLayoutRun.end() <= m_lastNonWhitespaceTextRun->end())
+            break;
+
+        // Full remove.
+        if (lastLayoutRun.start() >= m_lastNonWhitespaceTextRun->end()) {
+            m_trailingWhitespaceWidth -= lastLayoutRun.width();
+            m_layoutRuns.removeLast();
+            continue;
+        }
+        // Partial remove.
+        lastLayoutRun.setRight(lastLayoutRun.right() - m_trailingWhitespaceWidth);
+        lastLayoutRun.setEnd(m_lastNonWhitespaceTextRun->end());
+        m_trailingWhitespaceWidth = 0;
+    }
+}
+
+void SimpleLineBreaker::Line::reset()
+{
+    m_runsWidth = 0;
+    m_availableWidth = 0;
+    m_trailingWhitespaceWidth  = 0;
+    m_lastTextRun = std::nullopt;
+    m_lastNonWhitespaceTextRun = std::nullopt;
+}
+
+// FIXME: Use variable style based on the current text run.
+SimpleLineBreaker::Style::Style(const RenderStyle& style)
+    : wrapLines(style.autoWrap())
+    , breakAnyWordOnOverflow(style.wordBreak() == WordBreak::BreakAll && wrapLines)
+    , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || style.preserveNewline())))
+    , collapseWhitespace(style.collapseWhiteSpace())
+    , preWrap(wrapLines && !collapseWhitespace)
+    , preserveNewline(style.preserveNewline())
+    , textAlignIsRight(style.textAlign() == TextAlignMode::Right || style.textAlign() == TextAlignMode::WebKitRight)
+{
+}
+
+SimpleLineBreaker::SimpleLineBreaker(const Vector<TextRun>& textRuns, const TextContentProvider& contentProvider, LineConstraintList&& lineConstraintList, const RenderStyle& style)
+    : m_contentProvider(contentProvider)
+    , m_style(style)
+    , m_textRunList(textRuns)
+    , m_currentLine(m_layoutRuns)
+    , m_lineConstraintList(WTFMove(lineConstraintList))
+    , m_lineConstraintIterator(m_lineConstraintList)
+{
+    ASSERT(m_lineConstraintList.size());
+    // Since the height of the content is undefined, the last vertical position in the constraint list should always be infinite.
+    ASSERT(!m_lineConstraintList.last().verticalPosition);
+}
+
+Vector<LayoutRun> SimpleLineBreaker::runs()
+{
+    while (m_textRunList.current()) {
+        handleLineStart();
+        createRunsForLine();
+        handleLineEnd();
+    }
+
+    return m_layoutRuns;
+}
+
+void SimpleLineBreaker::handleLineEnd()
+{
+    if (!m_layoutRuns.isEmpty())
+        m_layoutRuns.last().setIsEndOfLine();
+    ++m_numberOfLines;
+    m_previousLineHasNonForcedContent = m_currentLine.hasContent() && m_currentLine.availableWidth() >= 0;
+    m_currentLine.reset();
+}
+
+void SimpleLineBreaker::handleLineStart()
+{
+    auto lineConstraint = this->lineConstraint(verticalPosition());
+    m_currentLine.setLeft(lineConstraint.left);
+    m_currentLine.setAvailableWidth(lineConstraint.right - lineConstraint.left);
+}
+
+void SimpleLineBreaker::createRunsForLine()
+{
+    collapseLeadingWhitespace();
+
+    while (auto textRun = m_textRunList.current()) {
+
+        if (!textRun->isLineBreak() && (!wrapContentOnOverflow() || m_currentLine.availableWidth() >= textRun->width())) {
+            m_currentLine.append(*textRun);
+            ++m_textRunList;
+            continue;
+        }
+
+        // This run is either a linebreak or it does not fit the current line.
+        if (textRun->isLineBreak()) {
+            // Add the new line only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.)
+            if (textRun->isHardLineBreak() || !m_currentLine.hasContent()) {
+                if (m_style.textAlignIsRight)
+                    m_currentLine.collapseTrailingWhitespace();
+                m_currentLine.append(*textRun);
+            }
+            ++m_textRunList;
+            break;
+        }
+
+        // Overflow wrapping behaviour:
+        // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
+        // 2. Whitespace collapse off: whitespace is wrapped.
+        // 3. First, non-whitespace run is either wrapped or kept on the line. (depends on overflow-wrap)
+        // 4. Non-whitespace run when there's already another run on the line either gets wrapped (word-break: break-all) or gets pushed to the next line.
+
+        // Whitespace run.
+        if (textRun->isWhitespace()) {
+            // Process collapsed whitespace again for the next line.
+            if (textRun->isCollapsed())
+                break;
+            // Try to split the whitespace; left part stays on this line, right is pushed to next line.
+            if (!splitTextRun(*textRun))
+                ++m_textRunList;
+            break;
+        }
+
+        // Non-whitespace run. (!style.wrapLines: bug138102(preserve existing behavior)
+        if (((!m_currentLine.hasContent() && m_style.breakFirstWordOnOverflow) || m_style.breakAnyWordOnOverflow) || !m_style.wrapLines) {
+            // Try to split the run; left side stays on this line, right side is pushed to next line.
+            if (!splitTextRun(*textRun))
+                ++m_textRunList;
+            break;
+        }
+
+        ASSERT(textRun->isNonWhitespace());
+        // Non-breakable non-whitespace first run. Add it to the current line. -it overflows though.
+        if (!m_currentLine.hasContent()) {
+            handleOverflownRun();
+            break;
+        }
+        // Non-breakable non-whitespace run when there's already content on the line. Process it on the next line.
+        break;
+    }
+
+    collapseTrailingWhitespace();
+}
+
+void SimpleLineBreaker::handleOverflownRun()
+{
+    auto textRun = m_textRunList.current();
+    ASSERT(textRun);
+
+    m_currentLine.append(*textRun);
+    ++m_textRunList;
+
+    // If the forced run is followed by a line break, we need to process it on this line, otherwise the next line would start with a line break (double line break).
+    // "foobarlongtext<br>foobar" should produce
+    // foobarlongtext
+    // foobar
+    // and not
+    // foobarlongtext
+    //
+    // foobar
+
+    // First check for collapsable whitespace.
+    textRun = m_textRunList.current();
+    if (!textRun)
+        return;
+
+    if (textRun->isWhitespace() && m_style.collapseWhitespace) {
+        ++m_textRunList;
+        textRun = m_textRunList.current();
+        if (!textRun)
+            return;
+    }
+
+    if (textRun->isHardLineBreak()) {
+        // <br> always produces a run. (required by testing output)
+        m_currentLine.append(*textRun);
+        ++m_textRunList;
+        return;
+    }
+
+    if (textRun->isSoftLineBreak() && !m_style.preserveNewline)
+        ++m_textRunList;
+}
+
+void SimpleLineBreaker::collapseLeadingWhitespace()
+{
+    auto textRun = m_textRunList.current();
+    if (!textRun || !textRun->isWhitespace())
+        return;
+
+    // Special overflow pre-wrap whitespace/newline handling for overflow whitespace: skip the leading whitespace/newline (even when style says not-collapsible)
+    // if we managed to put some content on the previous line.
+    if (m_textRunList.isCurrentOverridden()) {
+        auto collapseWhitespace = m_style.collapseWhitespace || m_style.preWrap;
+        if (collapseWhitespace && m_previousLineHasNonForcedContent) {
+            ++m_textRunList;
+            // If collapsing the whitespace puts us on a newline, skip the soft newline too as we already wrapped the line.
+            textRun = m_textRunList.current();
+            // <br> always produces a run. (required by testing output).
+            if (!textRun || textRun->isHardLineBreak())
+                return;
+            auto collapseSoftLineBreak = textRun->isSoftLineBreak() && (!m_style.preserveNewline || m_style.preWrap);
+            if (collapseSoftLineBreak) {
+                ++m_textRunList;
+                textRun = m_textRunList.current();
+            }
+        }
+    }
+
+    // Collapse leading whitespace if the style says so.
+    if (!m_style.collapseWhitespace)
+        return;
+
+    if (!textRun || !textRun->isWhitespace())
+        return;
+
+    ++m_textRunList;
+}
+
+void SimpleLineBreaker::collapseTrailingWhitespace()
+{
+    if (!m_currentLine.hasTrailingWhitespace())
+        return;
+
+    // Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce would produce an empty line.
+    bool collapseWhitespace = m_style.collapseWhitespace || m_style.preWrap;
+    if (!collapseWhitespace)
+        return;
+
+    // pre-wrap?
+    if (m_currentLine.isWhitespaceOnly() && m_style.preWrap)
+        return;
+
+    m_currentLine.collapseTrailingWhitespace();
+}
+
+bool SimpleLineBreaker::splitTextRun(const TextRun& textRun)
+{
+    // Single character handling.
+    if (textRun.start() + 1 == textRun.end()) {
+        // Keep at least one character on empty lines.
+        if (!m_currentLine.hasContent()) {
+            m_currentLine.append(textRun);
+            return false;
+        }
+        m_textRunList.overrideCurrent(textRun);
+        return true;
+    }
+
+    auto splitPair = split(textRun, m_currentLine.availableWidth());
+    m_currentLine.append(splitPair.left);
+    m_textRunList.overrideCurrent(splitPair.right);
+    return true;
+}
+
+TextRunSplitPair SimpleLineBreaker::split(const TextRun& textRun, float leftSideMaximumWidth) const
+{
+    // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
+    float leftSideWidth = 0;
+    auto left = textRun.start();
+
+    // Pathological case of (extremely)long string and narrow lines.
+    // Adjust the range so that we can pick a reasonable midpoint.
+    auto averageCharacterWidth = textRun.width() / textRun.length();
+    auto right = std::min<unsigned>(left + (2 * leftSideMaximumWidth / averageCharacterWidth), textRun.end() - 1);
+    while (left < right) {
+        auto middle = (left + right) / 2;
+        auto width = m_contentProvider.width(textRun.start(), middle + 1, 0);
+        if (width < leftSideMaximumWidth) {
+            left = middle + 1;
+            leftSideWidth = width;
+        } else if (width > leftSideMaximumWidth)
+            right = middle;
+        else {
+            right = middle + 1;
+            leftSideWidth = width;
+            break;
+        }
+    }
+
+    // Keep at least one character on empty lines.f
+    left = textRun.start();
+    if (left >= right && !m_currentLine.hasContent()) {
+        right = left + 1;
+        leftSideWidth = m_contentProvider.width(textRun.start(), right, 0);
+    }
+
+    auto rightSideWidth = m_contentProvider.width(right, textRun.end(), 0);
+    if (textRun.isNonWhitespace())
+        return { TextRun::createNonWhitespaceRun(left, right, leftSideWidth), TextRun::createNonWhitespaceRun(right, textRun.end(), rightSideWidth) };
+
+    // We never split collapsed whitespace.
+    ASSERT(textRun.isWhitespace());
+    ASSERT(!textRun.isCollapsed());
+    return { TextRun::createWhitespaceRun(left, right, leftSideWidth, false), TextRun::createWhitespaceRun(right, textRun.end(), rightSideWidth, false) };
+}
+
+SimpleLineBreaker::LineConstraint SimpleLineBreaker::lineConstraint(float verticalPosition)
+{
+    auto* lineConstraint = m_lineConstraintIterator.current();
+    if (!lineConstraint) {
+        ASSERT_NOT_REACHED();
+        return { };
+    }
+
+    while (lineConstraint->verticalPosition && verticalPosition > *lineConstraint->verticalPosition) {
+        lineConstraint = (++m_lineConstraintIterator).current();
+        if (!lineConstraint) {
+            // The vertical position of the last entry in the constraint list is supposed to be infinite.
+            ASSERT_NOT_REACHED();
+            return { };
+        }
+    }
+
+    return *lineConstraint;
+}
+
+}
+}
+#endif

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleLineBreaker.h (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleLineBreaker.h	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleLineBreaker.h	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 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
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "Runs.h"
+#include <wtf/IsoMalloc.h>
+
+namespace WebCore {
+
+class LayoutUnit;
+class RenderStyle;
+
+namespace Layout {
+
+class TextContentProvider;
+struct TextRunSplitPair;
+
+class SimpleLineBreaker {
+    WTF_MAKE_ISO_ALLOCATED(SimpleLineBreaker);
+public:
+    struct LineConstraint {
+        // verticalPosition sets the bottom edge for this constraint. Last entry in the list
+        // should always be std::nullopt indicating that left/right pair is set for the rest of the lines
+        // (Normally there's only one entry with the left/right block edges).
+        std::optional<float> verticalPosition;
+        float left { 0 };
+        float right { 0 };
+    };
+    using LineConstraintList = Vector<LineConstraint>;
+    SimpleLineBreaker(const Vector<TextRun>&, const TextContentProvider&, LineConstraintList&&, const RenderStyle&);
+
+    void setLineHeight(float lineHeight) { m_lineHeight = lineHeight; }
+
+    Vector<LayoutRun> runs();
+
+private:
+    struct Style {
+        explicit Style(const RenderStyle&);
+
+        bool wrapLines { false };
+        bool breakAnyWordOnOverflow { false };
+        bool breakFirstWordOnOverflow { false };
+        bool collapseWhitespace { false };
+        bool preWrap { false };
+        bool preserveNewline { false };
+        bool textAlignIsRight { false };
+    };
+
+    class TextRunList {
+    public:
+        TextRunList(const Vector<TextRun>& textRuns);
+
+        std::optional<TextRun> current() const;
+        TextRunList& operator++();
+
+        void overrideCurrent(TextRun textRun) { m_overrideTextRun = textRun; }
+        bool isCurrentOverridden() const { return m_overrideTextRun.has_value(); }
+
+    private:
+        const Vector<TextRun>& m_textRuns;
+        unsigned m_currentIndex { 0 };
+        std::optional<TextRun> m_overrideTextRun;
+    };
+
+    class Line {
+    public:
+        Line(Vector<LayoutRun>& layoutRuns);
+
+        void append(const TextRun&);
+        float availableWidth() const { return m_availableWidth - m_runsWidth; }
+        bool hasContent() const { return m_runsWidth; }
+
+        void reset();
+        void setAvailableWidth(float availableWidth) { m_availableWidth = availableWidth; }
+        bool hasTrailingWhitespace() const { return m_trailingWhitespaceWidth; }
+        bool isWhitespaceOnly() const { return m_runsWidth == m_trailingWhitespaceWidth; }
+        void collapseTrailingWhitespace();
+
+        void setLeft(float left) { m_left = left; }
+
+    private:
+        Vector<LayoutRun>& m_layoutRuns;
+        float m_runsWidth { 0 };
+        float m_availableWidth { 0 };
+        float m_left { 0 };
+        float m_trailingWhitespaceWidth { 0 };
+        std::optional<TextRun> m_lastTextRun;
+        std::optional<TextRun> m_lastNonWhitespaceTextRun;
+    };
+
+    void handleLineStart();
+    void handleLineEnd();
+    bool wrapContentOnOverflow() const { return m_style.wrapLines || m_style.breakFirstWordOnOverflow || m_style.breakAnyWordOnOverflow; }
+    void collectRuns();
+    void createRunsForLine();
+    void handleOverflownRun();
+    void collapseLeadingWhitespace();
+    void collapseTrailingWhitespace();
+    bool splitTextRun(const TextRun&);
+    TextRunSplitPair split(const TextRun&, float leftSideMaximumWidth) const;
+    LineConstraint lineConstraint(float verticalPosition);
+    float verticalPosition() const { return m_numberOfLines * m_lineHeight; }
+
+    const TextContentProvider& m_contentProvider;
+    const Style m_style;
+
+    TextRunList m_textRunList;
+
+    Line m_currentLine;
+    Vector<LayoutRun> m_layoutRuns;
+
+    LineConstraintList m_lineConstraintList;
+    ConstVectorIterator<LineConstraint> m_lineConstraintIterator;
+
+    unsigned m_numberOfLines { 0 };
+    bool m_previousLineHasNonForcedContent { false };
+    float m_lineHeight { 0 };
+};
+
+inline std::optional<TextRun> SimpleLineBreaker::TextRunList::current() const
+{
+    if (m_overrideTextRun)
+        return m_overrideTextRun;
+
+    if (m_currentIndex < m_textRuns.size())
+        return m_textRuns[m_currentIndex];
+
+    return { };
+}
+
+inline SimpleLineBreaker::TextRunList& SimpleLineBreaker::TextRunList::operator++()
+{
+    m_overrideTextRun = { };
+    ++m_currentIndex;
+    return *this;
+}
+
+}
+}
+#endif

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.cpp (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.cpp	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.cpp	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2018 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 "SimpleTextRunGenerator.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "BreakLines.h"
+#include "RenderStyle.h"
+#include "TextContentProvider.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(SimpleTextRunGenerator);
+
+SimpleTextRunGenerator::SimpleTextRunGenerator(const TextContentProvider& contentProvider)
+    : m_contentProvider(contentProvider)
+    , m_textIterator(m_contentProvider.textContent())
+    , m_hardLineBreakIterator(contentProvider.hardLineBreaks())
+{
+}
+
+std::optional<TextRun> SimpleTextRunGenerator::current() const
+{
+    // A run can either be
+    // 1. whitespace (collasped, non-collapsed multi or single)
+    // 2. non-whitespace
+    // 3. soft line break
+    // 4. hard line break
+    // 5. invalid
+    return m_currentRun;
+}
+
+void SimpleTextRunGenerator::reset()
+{
+    m_xPosition = 0;
+    m_currentRun = { };
+    m_currentPosition = { };
+}
+
+void SimpleTextRunGenerator::findNextRun()
+{
+    // End of content -not even trailing linebreaks?
+    if (m_currentPosition == m_contentProvider.length() && !m_hardLineBreakIterator.current()) {
+        m_currentRun = { };
+        return;
+    }
+
+    // Check if we are at a <br>.
+    while (auto* hardLineBreak = m_hardLineBreakIterator.current()) {
+        if (m_currentPosition < *hardLineBreak)
+            break;
+        if (m_currentPosition == *hardLineBreak) {
+            ++m_hardLineBreakIterator;
+            m_currentRun = TextRun::createHardLineBreakRun(m_currentPosition);
+            return;
+        }
+        ASSERT_NOT_REACHED();
+    }
+
+    // Soft linebreak?
+    if (isAtSoftLineBreak()) {
+        m_currentRun = TextRun::createSoftLineBreakRun(m_currentPosition);
+        ++m_currentPosition;
+        return;
+    }
+
+    auto startPosition = m_currentPosition;
+    auto isWhitespaceCollapsed = moveToNextNonWhitespacePosition();
+    // Whitespace?
+    if (m_currentPosition > startPosition) {
+        auto width = m_contentProvider.width(startPosition, isWhitespaceCollapsed ? startPosition + 1 : m_currentPosition, m_xPosition);
+        m_currentRun = TextRun::createWhitespaceRun(startPosition, m_currentPosition, width, isWhitespaceCollapsed);
+        m_xPosition += width;
+        return;
+    }
+
+    moveToNextBreakablePosition();
+    // nextBreakablePosition returns the same position for certain characters such as hyphens. Call next again with modified position.
+    auto skipCurrentPosition = m_currentPosition == startPosition;
+    if (skipCurrentPosition) {
+        ++m_currentPosition;
+        moveToNextBreakablePosition();
+    }
+    auto width = m_contentProvider.width(startPosition, m_currentPosition, m_xPosition);
+    m_currentRun = TextRun::createNonWhitespaceRun(startPosition, m_currentPosition, width);
+    m_xPosition += width;
+}
+
+void SimpleTextRunGenerator::moveToNextBreakablePosition()
+{
+    auto findNextBreakablePosition = [&](const TextContentProvider::TextItem& textItem, ItemPosition startPosition) {
+        // Swap iterator's content if we advanced to a new string.
+        auto iteratorText = m_lineBreakIterator.stringView();
+        if (iteratorText != textItem.text) {
+            auto textLength = iteratorText.length();
+            auto lastCharacter = textLength > 0 ? iteratorText[textLength - 1] : 0;
+            auto secondToLastCharacter = textLength > 1 ? iteratorText[textLength - 2] : 0;
+            m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
+            m_lineBreakIterator.resetStringAndReleaseIterator(textItem.text, textItem.style.locale, LineBreakIteratorMode::Default);
+        }
+
+        if (textItem.style.keepAllWordsForCJK) {
+            if (textItem.style.breakNBSP)
+                return nextBreakablePositionKeepingAllWords(m_lineBreakIterator, startPosition);
+            return nextBreakablePositionKeepingAllWordsIgnoringNBSP(m_lineBreakIterator, startPosition);
+        }
+
+        if (m_lineBreakIterator.mode() == LineBreakIteratorMode::Default) {
+            if (textItem.style.breakNBSP)
+                return WebCore::nextBreakablePosition(m_lineBreakIterator, startPosition);
+            return nextBreakablePositionIgnoringNBSP(m_lineBreakIterator, startPosition);
+        }
+
+        if (textItem.style.breakNBSP)
+            return nextBreakablePositionWithoutShortcut(m_lineBreakIterator, startPosition);
+        return nextBreakablePositionIgnoringNBSPWithoutShortcut(m_lineBreakIterator, startPosition);
+    };
+
+    while (auto* textItem = m_textIterator.current()) {
+        auto currentItemPosition = m_currentPosition.itemPosition();
+        auto nextBreakablePosition = findNextBreakablePosition(*textItem, currentItemPosition);
+        ASSERT(nextBreakablePosition >= currentItemPosition);
+        m_currentPosition += (nextBreakablePosition - currentItemPosition);
+        // Is the next breakable position still in this text?
+        auto textItemLength = textItem->end - textItem->start;
+        if (m_currentPosition.itemPosition() < textItemLength)
+            break;
+
+        // Hard line break inbetween?
+        if (isAtLineBreak())
+            break;
+
+        // Move over to the next text item.
+        m_currentPosition.resetItemPosition();
+        ++m_textIterator;
+    }
+}
+
+bool SimpleTextRunGenerator::moveToNextNonWhitespacePosition()
+{
+    auto startPosition = m_currentPosition;
+    auto collapseWhitespace = false;
+    while (auto* textItem = m_textIterator.current()) {
+        auto string = textItem->text;
+        auto preserveNewline = textItem->style.preserveNewline;
+        collapseWhitespace = textItem->style.collapseWhitespace;
+        for (; m_currentPosition.itemPosition() < string.length(); ++m_currentPosition) {
+            auto character = string[m_currentPosition.itemPosition()];
+            bool isWhitespace = character == ' ' || character == '\t' || (!preserveNewline && character == '\n');
+            if (!isWhitespace)
+                return collapseWhitespace && m_currentPosition - startPosition > 1;
+        }
+        // Check if there's a hard linebreak between text content.
+        if (isAtLineBreak())
+            break;
+
+        // Move over to the next text item.
+        m_currentPosition.resetItemPosition();
+        ++m_textIterator;
+    }
+
+    return collapseWhitespace && m_currentPosition - startPosition > 1;
+}
+
+bool SimpleTextRunGenerator::isAtLineBreak() const
+{
+    if (auto* currentHardLineBreakPosition = m_hardLineBreakIterator.current())
+        return *currentHardLineBreakPosition == m_currentPosition;
+    return isAtSoftLineBreak();
+}
+
+bool SimpleTextRunGenerator::isAtSoftLineBreak() const
+{
+    auto* textItem = m_textIterator.current();
+    if (!textItem)
+        return false;
+
+    if (!textItem->style.preserveNewline)
+        return false;
+
+    return textItem->text[m_currentPosition.itemPosition()] == '\n';
+}
+
+}
+}
+#endif

Added: trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.h (0 => 234000)


--- trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.h	                        (rev 0)
+++ trunk/Source/WebCore/layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.h	2018-07-19 20:36:13 UTC (rev 234000)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "TextContentProvider.h"
+#include <wtf/IsoMalloc.h>
+#include <wtf/text/TextBreakIterator.h>
+
+namespace WebCore {
+
+class RenderStyle;
+
+namespace Layout {
+
+class SimpleTextRunGenerator {
+    WTF_MAKE_ISO_ALLOCATED(SimpleTextRunGenerator);
+public:
+    SimpleTextRunGenerator(const TextContentProvider&);
+
+    void findNextRun();
+    std::optional<TextRun> current() const;
+    void reset();
+
+private:
+    void moveToNextBreakablePosition();
+    bool moveToNextNonWhitespacePosition();
+    bool isAtLineBreak() const;
+    bool isAtSoftLineBreak() const;
+    ItemPosition toItemPosition(ContentPosition) const;
+
+    struct Position {
+        Position() = default;
+
+        bool operator==(ContentPosition position) const { return m_contentPosition == position; }
+        bool operator<(ContentPosition position) const { return m_contentPosition < position; }
+        operator ContentPosition() const { return contentPosition(); }
+        Position& operator++();
+        Position& operator+=(unsigned);
+
+        void resetItemPosition() { m_itemPosition = 0; }
+
+        ContentPosition contentPosition() const { return m_contentPosition; }
+        ItemPosition itemPosition() const { return m_itemPosition; }
+
+    private:
+        ContentPosition m_contentPosition { 0 };
+        ItemPosition m_itemPosition { 0 };
+    };
+
+    const TextContentProvider& m_contentProvider;
+    ConstVectorIterator<TextContentProvider::TextItem> m_textIterator;
+    ConstVectorIterator<ContentPosition> m_hardLineBreakIterator;
+
+    Position m_currentPosition;
+    std::optional<TextRun> m_currentRun;
+    float m_xPosition { 0 };
+
+    LazyLineBreakIterator m_lineBreakIterator;
+};
+
+inline SimpleTextRunGenerator::Position& SimpleTextRunGenerator::Position::operator++()
+{
+    ++m_contentPosition;
+    ++m_itemPosition;
+    return *this;
+}
+
+inline SimpleTextRunGenerator::Position& SimpleTextRunGenerator::Position::operator+=(unsigned advance)
+{
+    m_contentPosition += advance;
+    m_itemPosition += advance;
+    return *this;
+}
+
+}
+}
+#endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to