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#pragma once
27
28#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
29
30#include "InlineItem.h"
31#include <wtf/IsoMalloc.h>
32#include <wtf/text/TextBreakIterator.h>
33
34namespace WebCore {
35namespace Layout {
36
37using ItemPosition = unsigned;
38
39class InlineRunProvider {
40 WTF_MAKE_ISO_ALLOCATED(InlineRunProvider);
41public:
42 InlineRunProvider();
43
44 void append(const InlineItem&);
45 void insertBefore(const Box&, const Box& before);
46 void remove(const Box&);
47
48 struct Run {
49
50 static Run createBoxRun(const InlineItem&);
51 static Run createFloatRun(const InlineItem&);
52 static Run createHardLineBreakRun(const InlineItem&);
53 static Run createSoftLineBreakRun(const InlineItem&);
54 static Run createWhitespaceRun(const InlineItem&, ItemPosition start, unsigned length, bool isCollapsible);
55 static Run createNonWhitespaceRun(const InlineItem&, ItemPosition start, unsigned length);
56
57 enum class Type {
58 Box,
59 Float,
60 SoftLineBreak,
61 HardLineBreak,
62 Whitespace,
63 NonWhitespace
64 };
65 Type type() const { return m_type; }
66 bool isText() const { return m_type == Run::Type::Whitespace || m_type == Run::Type::NonWhitespace || m_type == Run::Type::SoftLineBreak || m_type == Run::Type::HardLineBreak; }
67 bool isWhitespace() const { return m_type == Type::Whitespace; }
68 bool isNonWhitespace() const { return m_type == Type::NonWhitespace; }
69 bool isLineBreak() const { return m_type == Run::Type::SoftLineBreak || m_type == Run::Type::HardLineBreak; }
70 bool isBox() const { return m_type == Type::Box; }
71 bool isFloat() const { return m_type == Type::Float; }
72
73 struct TextContext {
74
75 enum class IsCollapsed { No, Yes };
76 TextContext(ItemPosition, unsigned length, IsCollapsed);
77
78 ItemPosition start() const { return m_start; }
79 // Note that 'end' position does not equal to start + length when run overlaps multiple InlineItems.
80 unsigned length() const { return m_length; }
81 bool isCollapsed() const { return m_isCollapsed == IsCollapsed::Yes; }
82
83 private:
84 friend class InlineRunProvider;
85
86 void expand(unsigned length) { m_length += length; }
87
88 ItemPosition m_start { 0 };
89 unsigned m_length { 0 };
90 IsCollapsed m_isCollapsed { IsCollapsed::No };
91 };
92 Optional<TextContext> textContext() const { return m_textContext; }
93 // Note that style() and inlineItem() always returns the first InlineItem for a run.
94 const RenderStyle& style() const { return m_inlineItem.style(); }
95 const InlineItem& inlineItem() const { return m_inlineItem; }
96
97 private:
98 friend class InlineRunProvider;
99
100 Run(const InlineItem&, Type, Optional<TextContext>);
101 Optional<TextContext>& textContext() { return m_textContext; }
102
103 const Type m_type;
104 const InlineItem& m_inlineItem;
105 Optional<TextContext> m_textContext;
106 };
107 const Vector<InlineRunProvider::Run>& runs() const { return m_inlineRuns; }
108
109private:
110 void commitTextRun();
111 void processInlineTextItem(const InlineItem&);
112 unsigned moveToNextNonWhitespacePosition(const InlineItem&, ItemPosition currentPosition);
113 unsigned moveToNextBreakablePosition(const InlineItem&, ItemPosition currentPosition);
114 bool isContinousContent(Run::Type newRunType, const InlineItem& newInlineItem);
115
116 LazyLineBreakIterator m_lineBreakIterator;
117
118 Vector<InlineRunProvider::Run> m_inlineRuns;
119};
120
121inline InlineRunProvider::Run InlineRunProvider::Run::createBoxRun(const InlineItem& inlineItem)
122{
123 return { inlineItem, Type::Box, WTF::nullopt };
124}
125
126inline InlineRunProvider::Run InlineRunProvider::Run::createFloatRun(const InlineItem& inlineItem)
127{
128 return { inlineItem, Type::Float, WTF::nullopt };
129}
130
131inline InlineRunProvider::Run InlineRunProvider::Run::createSoftLineBreakRun(const InlineItem& inlineItem)
132{
133 return { inlineItem, Type::SoftLineBreak, WTF::nullopt };
134}
135
136inline InlineRunProvider::Run InlineRunProvider::Run::createHardLineBreakRun(const InlineItem& inlineItem)
137{
138 return { inlineItem, Type::HardLineBreak, WTF::nullopt };
139}
140
141inline InlineRunProvider::Run InlineRunProvider::Run::createWhitespaceRun(const InlineItem& inlineItem, ItemPosition start, unsigned length, bool isCollapsible)
142{
143 ASSERT(length);
144 auto isCollapsed = isCollapsible && length > 1 ? TextContext::IsCollapsed::Yes : TextContext::IsCollapsed::No;
145 return { inlineItem, Type::Whitespace, TextContext(start, length, isCollapsed) };
146}
147
148inline InlineRunProvider::Run InlineRunProvider::Run::createNonWhitespaceRun(const InlineItem& inlineItem, ItemPosition start, unsigned length)
149{
150 return { inlineItem, Type::NonWhitespace, TextContext(start, length, TextContext::IsCollapsed::No) };
151}
152
153inline InlineRunProvider::Run::Run(const InlineItem& inlineItem, Type type, Optional<TextContext> textContext)
154 : m_type(type)
155 , m_inlineItem(inlineItem)
156 , m_textContext(textContext)
157{
158}
159
160inline InlineRunProvider::Run::TextContext::TextContext(ItemPosition start, unsigned length, IsCollapsed isCollapsed)
161 : m_start(start)
162 , m_length(length)
163 , m_isCollapsed(isCollapsed)
164{
165}
166
167}
168}
169#endif
170