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 | |
34 | namespace WebCore { |
35 | namespace Layout { |
36 | |
37 | using ItemPosition = unsigned; |
38 | |
39 | class InlineRunProvider { |
40 | WTF_MAKE_ISO_ALLOCATED(InlineRunProvider); |
41 | public: |
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 | |
109 | private: |
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 | |
121 | inline InlineRunProvider::Run InlineRunProvider::Run::createBoxRun(const InlineItem& inlineItem) |
122 | { |
123 | return { inlineItem, Type::Box, WTF::nullopt }; |
124 | } |
125 | |
126 | inline InlineRunProvider::Run InlineRunProvider::Run::createFloatRun(const InlineItem& inlineItem) |
127 | { |
128 | return { inlineItem, Type::Float, WTF::nullopt }; |
129 | } |
130 | |
131 | inline InlineRunProvider::Run InlineRunProvider::Run::createSoftLineBreakRun(const InlineItem& inlineItem) |
132 | { |
133 | return { inlineItem, Type::SoftLineBreak, WTF::nullopt }; |
134 | } |
135 | |
136 | inline InlineRunProvider::Run InlineRunProvider::Run::createHardLineBreakRun(const InlineItem& inlineItem) |
137 | { |
138 | return { inlineItem, Type::HardLineBreak, WTF::nullopt }; |
139 | } |
140 | |
141 | inline 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 | |
148 | inline 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 | |
153 | inline 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 | |
160 | inline 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 | |