[LFC][IFC] Add generic inline line breaker
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Oct 2018 16:31:19 +0000 (16:31 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Oct 2018 16:31:19 +0000 (16:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190698

Reviewed by Antti Koivisto.

InlineLineBreaker takes the inline runs and applies the appropriate line breaking rules on them.
InlineRunProvider::Run objects ->

    <foobar><image box><hello>< ><world>

InlineLineBreaker::Run ->

    <foobar><image box><hello world>

InlineLineBreaker::Run also contains information whether the run is at the beginning or at the end of the line.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/LayoutContext.h:
(WebCore::Layout::LayoutContext::hasDisplayBox const):
* layout/inlineformatting/InlineLineBreaker.cpp: Added.
(WebCore::Layout::InlineLineBreaker::InlineLineBreaker):
(WebCore::Layout::InlineLineBreaker::nextLayoutRun):
(WebCore::Layout::InlineLineBreaker::isAtContentEnd const):
(WebCore::Layout::InlineLineBreaker::lineBreakingBehavior):
(WebCore::Layout::InlineLineBreaker::runWidth const):
(WebCore::Layout::InlineLineBreaker::splitRun):
(WebCore::Layout::InlineLineBreaker::adjustSplitPositionWithHyphenation const):
* layout/inlineformatting/InlineLineBreaker.h: Added.
* layout/inlineformatting/textlayout/TextUtil.cpp: Added.
(WebCore::Layout::TextUtil::TextUtil):
(WebCore::Layout::TextUtil::width const):
(WebCore::Layout::TextUtil::hyphenPositionBefore const):
(WebCore::Layout::TextUtil::textWidth const):
(WebCore::Layout::TextUtil::fixedPitchWidth const):
* layout/inlineformatting/textlayout/TextUtil.h: Added.
* layout/layouttree/LayoutBox.cpp:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237287 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/layout/LayoutContext.h
Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp [new file with mode: 0644]
Source/WebCore/layout/inlineformatting/InlineLineBreaker.h [new file with mode: 0644]
Source/WebCore/layout/inlineformatting/textlayout/TextUtil.cpp [new file with mode: 0644]
Source/WebCore/layout/inlineformatting/textlayout/TextUtil.h [new file with mode: 0644]
Source/WebCore/layout/layouttree/LayoutBox.cpp

index de7960b..43960b7 100644 (file)
@@ -1,5 +1,45 @@
 2018-10-19  Zalan Bujtas  <zalan@apple.com>
 
+        [LFC][IFC] Add generic inline line breaker
+        https://bugs.webkit.org/show_bug.cgi?id=190698
+
+        Reviewed by Antti Koivisto.
+
+        InlineLineBreaker takes the inline runs and applies the appropriate line breaking rules on them.
+        InlineRunProvider::Run objects ->
+
+            <foobar><image box><hello>< ><world>
+
+        InlineLineBreaker::Run ->
+
+            <foobar><image box><hello world>
+
+        InlineLineBreaker::Run also contains information whether the run is at the beginning or at the end of the line.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/LayoutContext.h:
+        (WebCore::Layout::LayoutContext::hasDisplayBox const):
+        * layout/inlineformatting/InlineLineBreaker.cpp: Added.
+        (WebCore::Layout::InlineLineBreaker::InlineLineBreaker):
+        (WebCore::Layout::InlineLineBreaker::nextLayoutRun):
+        (WebCore::Layout::InlineLineBreaker::isAtContentEnd const):
+        (WebCore::Layout::InlineLineBreaker::lineBreakingBehavior):
+        (WebCore::Layout::InlineLineBreaker::runWidth const):
+        (WebCore::Layout::InlineLineBreaker::splitRun):
+        (WebCore::Layout::InlineLineBreaker::adjustSplitPositionWithHyphenation const):
+        * layout/inlineformatting/InlineLineBreaker.h: Added.
+        * layout/inlineformatting/textlayout/TextUtil.cpp: Added.
+        (WebCore::Layout::TextUtil::TextUtil):
+        (WebCore::Layout::TextUtil::width const):
+        (WebCore::Layout::TextUtil::hyphenPositionBefore const):
+        (WebCore::Layout::TextUtil::textWidth const):
+        (WebCore::Layout::TextUtil::fixedPitchWidth const):
+        * layout/inlineformatting/textlayout/TextUtil.h: Added.
+        * layout/layouttree/LayoutBox.cpp:
+
+2018-10-19  Zalan Bujtas  <zalan@apple.com>
+
         [LFC][IFC] Add generic inline run generator.
         https://bugs.webkit.org/show_bug.cgi?id=190696
 
index 9a079f4..c4cddc1 100644 (file)
@@ -1259,8 +1259,10 @@ layout/floats/FloatingState.cpp
 layout/inlineformatting/InlineFormattingContext.cpp
 layout/inlineformatting/InlineFormattingState.cpp
 layout/inlineformatting/InlineInvalidation.cpp
+layout/inlineformatting/InlineLineBreaker.cpp
 layout/inlineformatting/InlineRunProvider.cpp
 layout/inlineformatting/textlayout/TextContentProvider.cpp
+layout/inlineformatting/textlayout/TextUtil.cpp
 layout/inlineformatting/textlayout/simple/SimpleTextRunGenerator.cpp
 layout/inlineformatting/textlayout/simple/SimpleLineBreaker.cpp
 layout/layouttree/LayoutBlockContainer.cpp
index 1236da7..cbeb345 100644 (file)
                6F995A381A70833700A735F4 /* JSWebGLTransformFeedback.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F995A2E1A70833700A735F4 /* JSWebGLTransformFeedback.h */; };
                6F995A3A1A70833700A735F4 /* JSWebGLVertexArrayObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */; };
                6FA4454E898F2FC168BC38C1 /* JSBeforeUnloadEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 29E04A27BED2F81F98E9022B /* JSBeforeUnloadEvent.h */; };
+               6FB11B5C21783FD000E2A574 /* TextUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FB11B5921783FCF00E2A574 /* TextUtil.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE198152178397C00446F08 /* InlineLineBreaker.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6FE7CFA22177EEF2005B1573 /* InlineItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE7CFA02177EEF1005B1573 /* InlineItem.h */; };
                6FE7CFA42177EF10005B1573 /* LayoutLineBreakBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE7CFA32177EF10005B1573 /* LayoutLineBreakBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6FFDC442212EFF1700A9CA91 /* FloatAvoider.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FFDC440212EFF1600A9CA91 /* FloatAvoider.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6F995A2E1A70833700A735F4 /* JSWebGLTransformFeedback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLTransformFeedback.h; sourceTree = "<group>"; };
                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>"; };
+               6FB11B5921783FCF00E2A574 /* TextUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextUtil.h; sourceTree = "<group>"; };
+               6FB11B5B21783FCF00E2A574 /* TextUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextUtil.cpp; 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>"; };
+               6FE198132178397B00446F08 /* InlineLineBreaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineLineBreaker.cpp; sourceTree = "<group>"; };
+               6FE198152178397C00446F08 /* InlineLineBreaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineBreaker.h; sourceTree = "<group>"; };
                6FE7CFA02177EEF1005B1573 /* InlineItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineItem.h; sourceTree = "<group>"; };
                6FE7CFA32177EF10005B1573 /* LayoutLineBreakBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutLineBreakBox.h; sourceTree = "<group>"; };
                6FE7CFA52177F069005B1573 /* LayoutLineBreakBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutLineBreakBox.cpp; sourceTree = "<group>"; };
                115CFA9A208BC140001E6991 /* inlineformatting */ = {
                        isa = PBXGroup;
                        children = (
+                               6FE198132178397B00446F08 /* InlineLineBreaker.cpp */,
+                               6FE198152178397C00446F08 /* InlineLineBreaker.h */,
                                6FE7DDDD20EC6E8B008B5B4E /* textlayout */,
                                6F7CA3C9208C2B2E002F29AB /* InlineFormattingContext.cpp */,
                                6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */,
                6FE7DDDD20EC6E8B008B5B4E /* textlayout */ = {
                        isa = PBXGroup;
                        children = (
+                               6FB11B5B21783FCF00E2A574 /* TextUtil.cpp */,
+                               6FB11B5921783FCF00E2A574 /* TextUtil.h */,
                                6F13A12320F9949C001C025A /* simple */,
                                6FCF975220F02B3500214960 /* Runs.h */,
                                6FCD19C720F9727D00FD4529 /* TextContentProvider.cpp */,
                                A84EBD830CB8C97700079609 /* JSStyleSheetList.h in Headers */,
                                571F21891DA57C54005C9EFD /* JSSubtleCrypto.h in Headers */,
                                B20111080AB7740500DB0E68 /* JSSVGAElement.h in Headers */,
+                               6FB11B5C21783FD000E2A574 /* TextUtil.h in Headers */,
                                24D9129213CA951E00D21915 /* JSSVGAltGlyphDefElement.h in Headers */,
                                6515EC920D9723FF0063D49A /* JSSVGAltGlyphElement.h in Headers */,
                                24D9129613CA956100D21915 /* JSSVGAltGlyphItemElement.h in Headers */,
                                A88DD4870B4629A300C02990 /* PathTraversalState.h in Headers */,
                                2D5002FC1B56D7990020AAF7 /* PathUtilities.h in Headers */,
                                A8FA6E5D0E4CFDED00D5CF49 /* Pattern.h in Headers */,
+                               6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */,
                                B22279710D00BF220071B782 /* PatternAttributes.h in Headers */,
                                A1677E08213E024C00A08C34 /* PayerErrorFields.h in Headers */,
                                1A8A643A1D19FC5300D0E00F /* Payment.h in Headers */,
index e6f8f3b..c5875ec 100644 (file)
@@ -82,6 +82,7 @@ public:
     FormattingState& createFormattingStateForFormattingRootIfNeeded(const Box& formattingRoot);
 
     Display::Box& displayBoxForLayoutBox(const Box& layoutBox) const;
+    bool hasDisplayBox(const Box& layoutBox) const { return m_layoutToDisplayBox.contains(&layoutBox); }
 
     bool inQuirksMode() const { return m_inQuirksMode; }
     // For testing purposes only
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp
new file mode 100644 (file)
index 0000000..44fc2a1
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 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 "InlineLineBreaker.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FontCascade.h"
+#include "Hyphenation.h"
+#include "InlineRunProvider.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(InlineLineBreaker);
+
+InlineLineBreaker::InlineLineBreaker(const LayoutContext& layoutContext, const InlineContent& inlineContent, const Vector<InlineRunProvider::Run>& inlineRuns)
+    : m_layoutContext(layoutContext)
+    , m_textUtil(inlineContent)
+    , m_inlineRuns(inlineRuns)
+{
+}
+
+std::optional<InlineLineBreaker::Run> InlineLineBreaker::nextLayoutRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty)
+{
+    if (isAtContentEnd())
+        return std::nullopt;
+
+    InlineRunProvider::Run currentInlineRun = m_inlineRuns[m_currentRunIndex];
+    // Adjust the current run if it is split midword.
+    if (m_splitPosition) {
+        ASSERT(currentInlineRun.isText());
+        currentInlineRun.textContext()->setStart(*m_splitPosition);
+        m_splitPosition = std::nullopt;
+    }
+
+    if (currentInlineRun.isLineBreak()) {
+        ++m_currentRunIndex;
+        return Run { Run::Position::LineEnd, currentInlineRun, 0 };
+    }
+
+    auto contentWidth = runWidth(currentInlineRun, contentLogicalLeft);
+    // 1. Plenty of space left.
+    if (contentWidth <= availableWidth) {
+        ++m_currentRunIndex;
+        return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, currentInlineRun, contentWidth };
+    }
+
+    // 2. No space left whatsoever.
+    if (availableWidth <= 0) {
+        ++m_currentRunIndex;
+        return Run { Run::Position::LineBegin, currentInlineRun, contentWidth };
+    }
+
+    // 3. Some space left. Let's find out what we need to do with this run.
+    auto breakingBehavior = lineBreakingBehavior(currentInlineRun, lineIsEmpty);
+    if (breakingBehavior == LineBreakingBehavior::Keep) {
+        ++m_currentRunIndex;
+        return Run { lineIsEmpty ? Run::Position::LineBegin : Run::Position::Undetermined, currentInlineRun, contentWidth };
+    }
+
+    if (breakingBehavior == LineBreakingBehavior::WrapToNextLine) {
+        ++m_currentRunIndex;
+        return Run { Run::Position::LineBegin, currentInlineRun, contentWidth };
+    }
+
+    ASSERT(breakingBehavior == LineBreakingBehavior::Break);
+    // Split content.
+    return splitRun(currentInlineRun, contentLogicalLeft, availableWidth, lineIsEmpty);
+}
+
+bool InlineLineBreaker::isAtContentEnd() const
+{
+    return m_currentRunIndex == m_inlineRuns.size();
+}
+
+InlineLineBreaker::LineBreakingBehavior InlineLineBreaker::lineBreakingBehavior(const InlineRunProvider::Run& inlineRun, bool lineIsEmpty)
+{
+    // Line breaking behaviour:
+    // 1. Whitesapce collapse on -> push whitespace to next line.
+    // 2. Whitespace collapse off -> whitespace is split where possible.
+    // 3. Non-whitespace -> first run on the line -> either split or kept on the line. (depends on overflow-wrap)
+    // 4. Non-whitespace -> already content on the line -> either gets split (word-break: break-all) or gets pushed to the next line.
+    // (Hyphenate when possible)
+    // 5. Non-text type -> next line
+    auto& style = inlineRun.style();
+
+    if (inlineRun.isWhitespace())
+        return style.collapseWhiteSpace() ? LineBreakingBehavior::WrapToNextLine : LineBreakingBehavior::Break;
+
+    if (inlineRun.isNonWhitespace()) {
+        auto shouldHypenate = !m_hyphenationIsDisabled && style.hyphens() == Hyphens::Auto && canHyphenate(style.locale());
+        if (shouldHypenate)
+            return LineBreakingBehavior::Break;
+
+        if (style.autoWrap()) {
+            // Break any word
+            if (style.wordBreak() == WordBreak::BreakAll)
+                return LineBreakingBehavior::Break;
+
+            // Break first run on line.
+            if (lineIsEmpty && style.breakWords() && style.preserveNewline())
+                return LineBreakingBehavior::Break;
+        }
+
+        // Non-breakable non-whitespace run.
+        return lineIsEmpty ? LineBreakingBehavior::Keep : LineBreakingBehavior::WrapToNextLine;
+    }
+
+    ASSERT(inlineRun.isBox() || inlineRun.isFloat());
+    // Non-text inline runs.
+    return LineBreakingBehavior::WrapToNextLine;
+}
+
+LayoutUnit InlineLineBreaker::runWidth(const InlineRunProvider::Run& inlineRun, LayoutUnit contentLogicalLeft) const
+{
+    ASSERT(!inlineRun.isLineBreak());
+
+    if (inlineRun.isText()) {
+        auto textContext = inlineRun.textContext();
+        return m_textUtil.width(inlineRun.inlineItem(), textContext->start(), textContext->isCollapsed() ? 1 : textContext->length(), contentLogicalLeft);
+    }
+
+    ASSERT(inlineRun.isBox() || inlineRun.isFloat());
+    auto& layoutBox = inlineRun.inlineItem().layoutBox();
+    ASSERT(m_layoutContext.hasDisplayBox(layoutBox));
+    auto& displayBox = m_layoutContext.displayBoxForLayoutBox(layoutBox);
+    return displayBox.width();
+}
+
+InlineLineBreaker::Run InlineLineBreaker::splitRun(const InlineRunProvider::Run& inlineRun, LayoutUnit, LayoutUnit, bool)
+{
+    return { Run::Position::Undetermined, inlineRun, { } };
+}
+
+std::optional<ItemPosition> InlineLineBreaker::adjustSplitPositionWithHyphenation(const InlineRunProvider::Run&, ItemPosition, LayoutUnit, LayoutUnit, bool) const
+{
+    return { };
+}
+
+}
+}
+#endif
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h b/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h
new file mode 100644 (file)
index 0000000..ab01ada
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 "InlineRunProvider.h"
+#include "TextUtil.h"
+#include <wtf/IsoMalloc.h>
+
+namespace WebCore {
+namespace Layout {
+
+class InlineLineBreaker {
+    WTF_MAKE_ISO_ALLOCATED(InlineLineBreaker);
+public:
+    InlineLineBreaker(const LayoutContext&, const InlineContent&, const Vector<InlineRunProvider::Run>&);
+
+    struct Run {
+        enum class Position { Undetermined, LineBegin, LineEnd };
+        Position position;
+        InlineRunProvider::Run inlineRun;
+        LayoutUnit width;
+    };
+    std::optional<Run> nextLayoutRun(LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty);
+
+private:
+    enum class LineBreakingBehavior { Keep, Break, WrapToNextLine };
+    LineBreakingBehavior lineBreakingBehavior(const InlineRunProvider::Run&, bool lineIsEmpty);
+    bool isAtContentEnd() const;
+    Run splitRun(const InlineRunProvider::Run&, LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool lineIsEmpty);
+    LayoutUnit runWidth(const InlineRunProvider::Run&, LayoutUnit contentLogicalLeft) const;
+    std::optional<ItemPosition> adjustSplitPositionWithHyphenation(const InlineRunProvider::Run&, ItemPosition splitPosition, LayoutUnit contentLogicalLeft, LayoutUnit availableWidth, bool isLineEmpty) const;
+
+    const LayoutContext& m_layoutContext;
+    const TextUtil m_textUtil;
+    const Vector<InlineRunProvider::Run>& m_inlineRuns;
+
+    unsigned m_currentRunIndex { 0 };
+    std::optional<ItemPosition> m_splitPosition;
+    bool m_hyphenationIsDisabled { false };
+};
+
+}
+}
+#endif
diff --git a/Source/WebCore/layout/inlineformatting/textlayout/TextUtil.cpp b/Source/WebCore/layout/inlineformatting/textlayout/TextUtil.cpp
new file mode 100644 (file)
index 0000000..d6513fe
--- /dev/null
@@ -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.
+ */
+
+#include "config.h"
+#include "TextUtil.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FontCascade.h"
+#include "RenderStyle.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(TextUtil);
+
+TextUtil::TextUtil(const InlineContent& inlineContent)
+    : m_inlineContent(inlineContent)
+{
+}
+
+LayoutUnit TextUtil::width(const InlineItem& inlineItem, ItemPosition from, unsigned length, LayoutUnit contentLogicalLeft) const
+{
+    LayoutUnit width;
+    auto startPosition = from;
+    auto iterator = m_inlineContent.find<const InlineItem&, InlineItemHashTranslator>(inlineItem);
+    auto inlineItemEnd = m_inlineContent.end();
+    while (length) {
+        ASSERT(iterator != inlineItemEnd);
+        auto& currentInlineItem = **iterator;
+        auto endPosition = std::min<ItemPosition>(startPosition + length, currentInlineItem.textContent().length());
+        auto textWidth = this->textWidth(currentInlineItem, startPosition, endPosition, contentLogicalLeft);
+
+        contentLogicalLeft += textWidth;
+        width += textWidth;
+        length -= (endPosition - startPosition);
+
+        startPosition = 0;
+        ++iterator;
+    }
+
+    return width;
+}
+
+std::optional<ItemPosition> TextUtil::hyphenPositionBefore(const InlineItem&, ItemPosition, unsigned) const
+{
+    return std::nullopt;
+}
+
+LayoutUnit TextUtil::textWidth(const InlineItem& inlineTextItem, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft) const
+{
+    auto& style = inlineTextItem.style();
+    auto& font = style.fontCascade();
+    if (!font.size() || from == to)
+        return 0;
+
+    auto text = inlineTextItem.textContent();
+    if (font.isFixedPitch())
+        return fixedPitchWidth(text, style, from, to, contentLogicalLeft);
+
+    auto hasKerningOrLigatures = font.enableKerning() || font.requiresShaping();
+    auto measureWithEndSpace = hasKerningOrLigatures && to < text.length() && text[to] == ' ';
+    if (measureWithEndSpace)
+        ++to;
+    LayoutUnit width;
+    auto tabWidth = style.collapseWhiteSpace() ? 0 : style.tabSize();
+
+    WebCore::TextRun run(StringView(text).substring(from, to - from), contentLogicalLeft);
+    if (tabWidth)
+        run.setTabSize(true, tabWidth);
+    width = font.width(run);
+
+    if (measureWithEndSpace)
+        width -= (font.spaceWidth() + font.wordSpacing());
+
+    return std::max<LayoutUnit>(0, width);
+}
+
+LayoutUnit TextUtil::fixedPitchWidth(String text, const RenderStyle& style, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft) const
+{
+    auto& font = style.fontCascade();
+    auto monospaceCharacterWidth = font.spaceWidth();
+    LayoutUnit width;
+    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 : font.tabWidth(style.tabSize(), contentLogicalLeft + width);
+
+        if (i > from && (character == ' ' || character == '\t' || character == '\n'))
+            width += font.wordSpacing();
+    }
+
+    return width;
+}
+
+}
+}
+#endif
diff --git a/Source/WebCore/layout/inlineformatting/textlayout/TextUtil.h b/Source/WebCore/layout/inlineformatting/textlayout/TextUtil.h
new file mode 100644 (file)
index 0000000..fd75cbc
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 "InlineItem.h"
+#include <wtf/IsoMalloc.h>
+
+namespace WebCore {
+
+namespace Layout {
+
+class TextUtil {
+    WTF_MAKE_ISO_ALLOCATED(TextUtil);
+public:
+    TextUtil(const InlineContent&);
+
+    LayoutUnit width(const InlineItem&, ItemPosition from, unsigned length, LayoutUnit contentLogicalLeft) const;
+    std::optional<ItemPosition> hyphenPositionBefore(const InlineItem&, ItemPosition from, unsigned length) const;
+
+private:
+    LayoutUnit textWidth(const InlineItem&, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft) const;
+    LayoutUnit fixedPitchWidth(String, const RenderStyle&, ItemPosition from, ItemPosition to, LayoutUnit contentLogicalLeft) const;
+
+    const InlineContent& m_inlineContent;
+};
+
+}
+}
+#endif
index e1d26fa..05df2c8 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
+#include "LayoutContainer.h"
 #include "RenderStyle.h"
 #include <wtf/IsoMallocInlines.h>