[LFC][IFC] Move some code from InlineFormattingContext::Line to InlineFormattingConte...
[WebKit-https.git] / Source / WebCore / layout / inlineformatting / Line.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "InlineFormattingContext.h"
28 #include "InlineFormattingState.h"
29 #include "InlineRunProvider.h"
30
31 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
32
33 namespace WebCore {
34 namespace Layout {
35
36 InlineFormattingContext::Line::Line(InlineFormattingState& formattingState)
37     : m_formattingState(formattingState)
38 {
39 }
40
41 void InlineFormattingContext::Line::init(const Display::Box::Rect& logicalRect)
42 {
43     m_logicalRect = logicalRect;
44     m_availableWidth = logicalRect.width();
45
46     m_firstRunIndex = { };
47     m_lastRunType = { };
48     m_lastRunCanExpand = false;
49     m_trailingTrimmableContent = { };
50     m_closed = false;
51 }
52
53 void InlineFormattingContext::Line::adjustLogicalLeft(LayoutUnit delta)
54 {
55     ASSERT(delta > 0);
56
57     m_availableWidth -= delta;
58     m_logicalRect.shiftLeftTo(m_logicalRect.left() + delta);
59
60     if (!m_firstRunIndex)
61         return;
62
63     auto& inlineRuns = m_formattingState.inlineRuns();
64     for (auto runIndex = *m_firstRunIndex; runIndex < inlineRuns.size(); ++runIndex)
65         inlineRuns[runIndex].moveHorizontally(delta);
66 }
67
68 void InlineFormattingContext::Line::adjustLogicalRight(LayoutUnit delta)
69 {
70     ASSERT(delta > 0);
71
72     m_availableWidth -= delta;
73     m_logicalRect.shiftRightTo(m_logicalRect.right() - delta);
74 }
75
76 static bool isTrimmableContent(const InlineRunProvider::Run& inlineRun)
77 {
78     return inlineRun.isWhitespace() && inlineRun.style().collapseWhiteSpace();
79 }
80
81 LayoutUnit InlineFormattingContext::Line::contentLogicalRight() const
82 {
83     if (!m_firstRunIndex.has_value())
84         return m_logicalRect.left();
85
86     return m_formattingState.inlineRuns().last().logicalRight();
87 }
88
89 void InlineFormattingContext::Line::appendContent(const InlineLineBreaker::Run& run)
90 {
91     ASSERT(!isClosed());
92
93     auto& content = run.content;
94
95     // Append this text run to the end of the last text run, if the last run is continuous.
96     std::optional<InlineRun::TextContext> textRun;
97     if (content.isText()) {
98         auto textContext = content.textContext();
99         auto runLength = textContext->isCollapsed() ? 1 : textContext->length();
100         textRun = InlineRun::TextContext { textContext->start(), runLength };
101     }
102
103     auto requiresNewInlineRun = !hasContent() || !content.isText() || !m_lastRunCanExpand;
104     if (requiresNewInlineRun) {
105         // FIXME: This needs proper baseline handling
106         auto inlineRun = InlineRun { { logicalTop(), contentLogicalRight(), run.width, logicalBottom() - logicalTop() }, content.inlineItem() };
107         if (textRun)
108             inlineRun.setTextContext({ textRun->start(), textRun->length() });
109         m_formattingState.appendInlineRun(inlineRun);
110     } else {
111         // Non-text runs always require new inline run.
112         ASSERT(textRun);
113         auto& inlineRun = m_formattingState.inlineRuns().last();
114         inlineRun.setWidth(inlineRun.width() + run.width);
115         inlineRun.textContext()->setLength(inlineRun.textContext()->length() + textRun->length());
116     }
117
118     m_availableWidth -= run.width;
119     m_lastRunType = content.type();
120     m_lastRunCanExpand = content.isText() && !content.textContext()->isCollapsed();
121     m_firstRunIndex = m_firstRunIndex.value_or(m_formattingState.inlineRuns().size() - 1);
122     m_trailingTrimmableContent = { };
123     if (isTrimmableContent(content))
124         m_trailingTrimmableContent = TrailingTrimmableContent { run.width, textRun->length() };
125 }
126
127 InlineFormattingContext::Line::RunRange InlineFormattingContext::Line::close()
128 {
129     auto trimTrailingContent = [&]{
130
131         if (!m_trailingTrimmableContent)
132             return;
133
134         auto& lastInlineRun = m_formattingState.inlineRuns().last();
135         lastInlineRun.setWidth(lastInlineRun.width() - m_trailingTrimmableContent->width);
136         lastInlineRun.textContext()->setLength(lastInlineRun.textContext()->length() - m_trailingTrimmableContent->length);
137
138         if (!lastInlineRun.textContext()->length()) {
139             if (*m_firstRunIndex == m_formattingState.inlineRuns().size() - 1)
140                 m_firstRunIndex = { };
141             m_formattingState.inlineRuns().removeLast();
142         }
143         m_availableWidth += m_trailingTrimmableContent->width;
144         m_trailingTrimmableContent = { };
145     };
146
147     if (!hasContent())
148         return { };
149
150     trimTrailingContent();
151     m_isFirstLine = false;
152     m_closed = true;
153
154     if (!m_firstRunIndex)
155         return { };
156     return { m_firstRunIndex, m_formattingState.inlineRuns().size() - 1 };
157 }
158
159 }
160 }
161
162 #endif