/src/mozilla-central/layout/generic/RubyUtils.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_RubyUtils_h_ |
8 | | #define mozilla_RubyUtils_h_ |
9 | | |
10 | | #include "nsCSSAnonBoxes.h" |
11 | | #include "nsGkAtoms.h" |
12 | | #include "nsIFrame.h" |
13 | | #include "nsTArray.h" |
14 | | |
15 | | #define RTC_ARRAY_SIZE 1 |
16 | | |
17 | | class nsRubyFrame; |
18 | | class nsRubyBaseFrame; |
19 | | class nsRubyTextFrame; |
20 | | class nsRubyContentFrame; |
21 | | class nsRubyBaseContainerFrame; |
22 | | class nsRubyTextContainerFrame; |
23 | | |
24 | | namespace mozilla { |
25 | | |
26 | | /** |
27 | | * Reserved ISize |
28 | | * |
29 | | * With some exceptions, each ruby internal box has two isizes, which |
30 | | * are the reflowed isize and the final isize. The reflowed isize is |
31 | | * what a box itself needs. It is determined when the box gets reflowed. |
32 | | * |
33 | | * The final isize is what a box should be as the final result. For a |
34 | | * ruby base/text box, the final isize is the size of its ruby column. |
35 | | * For a ruby base/text container, the final isize is the size of its |
36 | | * ruby segment. The final isize is never smaller than the reflowed |
37 | | * isize. It is initially determined when a ruby column/segment gets |
38 | | * fully reflowed, and may be advanced when a box is expanded, e.g. |
39 | | * for justification. |
40 | | * |
41 | | * The difference between the reflowed isize and the final isize is |
42 | | * reserved in the line layout after reflowing a box, hence it is called |
43 | | * "Reserved ISize" here. It is used to expand the ruby boxes from their |
44 | | * reflowed isize to the final isize during alignment of the line. |
45 | | * |
46 | | * There are three exceptions for the final isize: |
47 | | * 1. A ruby text container has a larger final isize only if it is for |
48 | | * a span or collapsed annotations. |
49 | | * 2. A ruby base container has a larger final isize only if at least |
50 | | * one of its ruby text containers does. |
51 | | * 3. If a ruby text container has a larger final isize, its children |
52 | | * must not have. |
53 | | */ |
54 | | |
55 | | class RubyUtils |
56 | | { |
57 | | public: |
58 | | static inline bool IsRubyContentBox(LayoutFrameType aFrameType) |
59 | 0 | { |
60 | 0 | return aFrameType == mozilla::LayoutFrameType::RubyBase || |
61 | 0 | aFrameType == mozilla::LayoutFrameType::RubyText; |
62 | 0 | } |
63 | | |
64 | | static inline bool IsRubyContainerBox(LayoutFrameType aFrameType) |
65 | 0 | { |
66 | 0 | return aFrameType == mozilla::LayoutFrameType::RubyBaseContainer || |
67 | 0 | aFrameType == mozilla::LayoutFrameType::RubyTextContainer; |
68 | 0 | } |
69 | | |
70 | | static inline bool IsRubyBox(LayoutFrameType aFrameType) |
71 | 0 | { |
72 | 0 | return aFrameType == mozilla::LayoutFrameType::Ruby || |
73 | 0 | IsRubyContentBox(aFrameType) || IsRubyContainerBox(aFrameType); |
74 | 0 | } |
75 | | |
76 | | static inline bool IsExpandableRubyBox(nsIFrame* aFrame) |
77 | 0 | { |
78 | 0 | mozilla::LayoutFrameType type = aFrame->Type(); |
79 | 0 | return IsRubyContentBox(type) || IsRubyContainerBox(type); |
80 | 0 | } |
81 | | |
82 | | static inline bool IsRubyPseudo(nsAtom* aPseudo) |
83 | 0 | { |
84 | 0 | return aPseudo == nsCSSAnonBoxes::ruby() || |
85 | 0 | aPseudo == nsCSSAnonBoxes::rubyBase() || |
86 | 0 | aPseudo == nsCSSAnonBoxes::rubyText() || |
87 | 0 | aPseudo == nsCSSAnonBoxes::rubyBaseContainer() || |
88 | 0 | aPseudo == nsCSSAnonBoxes::rubyTextContainer(); |
89 | 0 | } |
90 | | |
91 | | static void SetReservedISize(nsIFrame* aFrame, nscoord aISize); |
92 | | static void ClearReservedISize(nsIFrame* aFrame); |
93 | | static nscoord GetReservedISize(nsIFrame* aFrame); |
94 | | }; |
95 | | |
96 | | /** |
97 | | * This array stores all ruby text containers of the ruby segment |
98 | | * of the given ruby base container. |
99 | | */ |
100 | | class MOZ_RAII AutoRubyTextContainerArray final |
101 | | : public AutoTArray<nsRubyTextContainerFrame*, RTC_ARRAY_SIZE> |
102 | | { |
103 | | public: |
104 | | explicit AutoRubyTextContainerArray(nsRubyBaseContainerFrame* aBaseContainer); |
105 | | }; |
106 | | |
107 | | /** |
108 | | * This enumerator enumerates each ruby segment. |
109 | | */ |
110 | | class MOZ_STACK_CLASS RubySegmentEnumerator |
111 | | { |
112 | | public: |
113 | | explicit RubySegmentEnumerator(nsRubyFrame* aRubyFrame); |
114 | | |
115 | | void Next(); |
116 | 0 | bool AtEnd() const { return !mBaseContainer; } |
117 | | |
118 | | nsRubyBaseContainerFrame* GetBaseContainer() const |
119 | 0 | { |
120 | 0 | return mBaseContainer; |
121 | 0 | } |
122 | | |
123 | | private: |
124 | | nsRubyBaseContainerFrame* mBaseContainer; |
125 | | }; |
126 | | |
127 | | /** |
128 | | * Ruby column is a unit consists of one ruby base and all ruby |
129 | | * annotations paired with it. |
130 | | * See http://dev.w3.org/csswg/css-ruby/#ruby-pairing |
131 | | */ |
132 | | struct MOZ_STACK_CLASS RubyColumn |
133 | | { |
134 | | nsRubyBaseFrame* mBaseFrame; |
135 | | AutoTArray<nsRubyTextFrame*, RTC_ARRAY_SIZE> mTextFrames; |
136 | | bool mIsIntraLevelWhitespace; |
137 | | |
138 | 0 | RubyColumn() : mBaseFrame(nullptr), mIsIntraLevelWhitespace(false) { } |
139 | | |
140 | | // Helper class to support iteration across the frames within a single |
141 | | // RubyColumn (the column's ruby base and its annotations). |
142 | | class MOZ_STACK_CLASS Iterator |
143 | | { |
144 | | public: |
145 | | nsIFrame* operator*() const; |
146 | | |
147 | 0 | Iterator& operator++() { ++mIndex; SkipUntilExistingFrame(); return *this; } |
148 | 0 | Iterator operator++(int) { auto ret = *this; ++*this; return ret; } |
149 | | |
150 | | friend bool operator==(const Iterator& aIter1, const Iterator& aIter2) |
151 | 0 | { |
152 | 0 | MOZ_ASSERT(&aIter1.mColumn == &aIter2.mColumn, |
153 | 0 | "Should only compare iterators of the same ruby column"); |
154 | 0 | return aIter1.mIndex == aIter2.mIndex; |
155 | 0 | } |
156 | | friend bool operator!=(const Iterator& aIter1, const Iterator& aIter2) |
157 | 0 | { |
158 | 0 | return !(aIter1 == aIter2); |
159 | 0 | } |
160 | | |
161 | | private: |
162 | | Iterator(const RubyColumn& aColumn, int32_t aIndex) |
163 | | : mColumn(aColumn) |
164 | | , mIndex(aIndex) |
165 | 0 | { |
166 | 0 | MOZ_ASSERT(aIndex == -1 || |
167 | 0 | (aIndex >= 0 && |
168 | 0 | aIndex <= int32_t(aColumn.mTextFrames.Length()))); |
169 | 0 | SkipUntilExistingFrame(); |
170 | 0 | } |
171 | | friend struct RubyColumn; // for the constructor |
172 | | |
173 | | void SkipUntilExistingFrame(); |
174 | | |
175 | | const RubyColumn& mColumn; |
176 | | // -1 means the ruby base frame, |
177 | | // non-negative means the index of ruby text frame |
178 | | // a value of mTextFrames.Length() means we're done iterating |
179 | | int32_t mIndex = -1; |
180 | | }; |
181 | | |
182 | 0 | Iterator begin() const { return Iterator(*this, -1); } |
183 | 0 | Iterator end() const { return Iterator(*this, mTextFrames.Length()); } |
184 | 0 | Iterator cbegin() const { return begin(); } |
185 | 0 | Iterator cend() const { return end(); } |
186 | | }; |
187 | | |
188 | | /** |
189 | | * This enumerator enumerates ruby columns in a segment. |
190 | | */ |
191 | | class MOZ_STACK_CLASS RubyColumnEnumerator |
192 | | { |
193 | | public: |
194 | | RubyColumnEnumerator(nsRubyBaseContainerFrame* aRBCFrame, |
195 | | const AutoRubyTextContainerArray& aRTCFrames); |
196 | | |
197 | | void Next(); |
198 | | bool AtEnd() const; |
199 | | |
200 | 0 | uint32_t GetLevelCount() const { return mFrames.Length(); } |
201 | | nsRubyContentFrame* GetFrameAtLevel(uint32_t aIndex) const; |
202 | | void GetColumn(RubyColumn& aColumn) const; |
203 | | |
204 | | private: |
205 | | // Frames in this array are NOT necessary part of the current column. |
206 | | // When in doubt, use GetFrameAtLevel to access it. |
207 | | // See GetFrameAtLevel() and Next() for more info. |
208 | | AutoTArray<nsRubyContentFrame*, RTC_ARRAY_SIZE + 1> mFrames; |
209 | | // Whether we are on a column for intra-level whitespaces |
210 | | bool mAtIntraLevelWhitespace; |
211 | | }; |
212 | | |
213 | | /** |
214 | | * Stores block-axis leadings produced from ruby annotations. |
215 | | */ |
216 | | struct RubyBlockLeadings |
217 | | { |
218 | | nscoord mStart = 0; |
219 | | nscoord mEnd = 0; |
220 | | |
221 | 0 | void Reset() { |
222 | 0 | mStart = mEnd = 0; |
223 | 0 | } |
224 | 0 | void Update(nscoord aStart, nscoord aEnd) { |
225 | 0 | mStart = std::max(mStart, aStart); |
226 | 0 | mEnd = std::max(mEnd, aEnd); |
227 | 0 | } |
228 | 0 | void Update(const RubyBlockLeadings& aOther) { |
229 | 0 | Update(aOther.mStart, aOther.mEnd); |
230 | 0 | } |
231 | | }; |
232 | | |
233 | | } // namespace mozilla |
234 | | |
235 | | #endif /* !defined(mozilla_RubyUtils_h_) */ |