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