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/. */
7 #ifndef mozilla_RubyUtils_h_
8 #define mozilla_RubyUtils_h_
10 #include "nsCSSAnonBoxes.h"
11 #include "nsGkAtoms.h"
15 #define RTC_ARRAY_SIZE 1
18 class nsRubyBaseFrame
;
19 class nsRubyTextFrame
;
20 class nsRubyContentFrame
;
21 class nsRubyBaseContainerFrame
;
22 class nsRubyTextContainerFrame
;
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.
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.
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.
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
57 static inline bool IsRubyContentBox(LayoutFrameType aFrameType
) {
58 return aFrameType
== mozilla::LayoutFrameType::RubyBase
||
59 aFrameType
== mozilla::LayoutFrameType::RubyText
;
62 static inline bool IsRubyContainerBox(LayoutFrameType aFrameType
) {
63 return aFrameType
== mozilla::LayoutFrameType::RubyBaseContainer
||
64 aFrameType
== mozilla::LayoutFrameType::RubyTextContainer
;
67 static inline bool IsRubyBox(LayoutFrameType aFrameType
) {
68 return aFrameType
== mozilla::LayoutFrameType::Ruby
||
69 IsRubyContentBox(aFrameType
) || IsRubyContainerBox(aFrameType
);
72 static inline bool IsExpandableRubyBox(nsIFrame
* aFrame
) {
73 mozilla::LayoutFrameType type
= aFrame
->Type();
74 return IsRubyContentBox(type
) || IsRubyContainerBox(type
);
77 static inline bool IsRubyPseudo(PseudoStyleType aPseudo
) {
78 return aPseudo
== PseudoStyleType::blockRubyContent
||
79 aPseudo
== PseudoStyleType::ruby
||
80 aPseudo
== PseudoStyleType::rubyBase
||
81 aPseudo
== PseudoStyleType::rubyText
||
82 aPseudo
== PseudoStyleType::rubyBaseContainer
||
83 aPseudo
== PseudoStyleType::rubyTextContainer
;
86 static void SetReservedISize(nsIFrame
* aFrame
, nscoord aISize
);
87 static void ClearReservedISize(nsIFrame
* aFrame
);
88 static nscoord
GetReservedISize(nsIFrame
* aFrame
);
92 * This array stores all ruby text containers of the ruby segment
93 * of the given ruby base container.
95 class MOZ_RAII AutoRubyTextContainerArray final
96 : public AutoTArray
<nsRubyTextContainerFrame
*, RTC_ARRAY_SIZE
> {
98 explicit AutoRubyTextContainerArray(nsRubyBaseContainerFrame
* aBaseContainer
);
102 * This enumerator enumerates each ruby segment.
104 class MOZ_STACK_CLASS RubySegmentEnumerator
{
106 explicit RubySegmentEnumerator(nsRubyFrame
* aRubyFrame
);
109 bool AtEnd() const { return !mBaseContainer
; }
111 nsRubyBaseContainerFrame
* GetBaseContainer() const { return mBaseContainer
; }
114 nsRubyBaseContainerFrame
* mBaseContainer
;
118 * Ruby column is a unit consists of one ruby base and all ruby
119 * annotations paired with it.
120 * See http://dev.w3.org/csswg/css-ruby/#ruby-pairing
122 struct MOZ_STACK_CLASS RubyColumn
{
123 nsRubyBaseFrame
* mBaseFrame
;
124 AutoTArray
<nsRubyTextFrame
*, RTC_ARRAY_SIZE
> mTextFrames
;
125 bool mIsIntraLevelWhitespace
;
127 RubyColumn() : mBaseFrame(nullptr), mIsIntraLevelWhitespace(false) {}
129 // Helper class to support iteration across the frames within a single
130 // RubyColumn (the column's ruby base and its annotations).
131 class MOZ_STACK_CLASS Iterator
{
133 nsIFrame
* operator*() const;
135 Iterator
& operator++() {
137 SkipUntilExistingFrame();
140 Iterator
operator++(int) {
146 friend bool operator==(const Iterator
& aIter1
, const Iterator
& aIter2
) {
147 MOZ_ASSERT(&aIter1
.mColumn
== &aIter2
.mColumn
,
148 "Should only compare iterators of the same ruby column");
149 return aIter1
.mIndex
== aIter2
.mIndex
;
151 friend bool operator!=(const Iterator
& aIter1
, const Iterator
& aIter2
) {
152 return !(aIter1
== aIter2
);
156 Iterator(const RubyColumn
& aColumn
, int32_t aIndex
)
157 : mColumn(aColumn
), mIndex(aIndex
) {
160 (aIndex
>= 0 && aIndex
<= int32_t(aColumn
.mTextFrames
.Length())));
161 SkipUntilExistingFrame();
163 friend struct RubyColumn
; // for the constructor
165 void SkipUntilExistingFrame();
167 const RubyColumn
& mColumn
;
168 // -1 means the ruby base frame,
169 // non-negative means the index of ruby text frame
170 // a value of mTextFrames.Length() means we're done iterating
174 Iterator
begin() const { return Iterator(*this, -1); }
175 Iterator
end() const { return Iterator(*this, mTextFrames
.Length()); }
176 Iterator
cbegin() const { return begin(); }
177 Iterator
cend() const { return end(); }
181 * This enumerator enumerates ruby columns in a segment.
183 class MOZ_STACK_CLASS RubyColumnEnumerator
{
185 RubyColumnEnumerator(nsRubyBaseContainerFrame
* aRBCFrame
,
186 const AutoRubyTextContainerArray
& aRTCFrames
);
191 uint32_t GetLevelCount() const { return mFrames
.Length(); }
192 nsRubyContentFrame
* GetFrameAtLevel(uint32_t aIndex
) const;
193 void GetColumn(RubyColumn
& aColumn
) const;
196 // Frames in this array are NOT necessary part of the current column.
197 // When in doubt, use GetFrameAtLevel to access it.
198 // See GetFrameAtLevel() and Next() for more info.
199 AutoTArray
<nsRubyContentFrame
*, RTC_ARRAY_SIZE
+ 1> mFrames
;
200 // Whether we are on a column for intra-level whitespaces
201 bool mAtIntraLevelWhitespace
;
205 * Stores block-axis leadings produced from ruby annotations.
207 struct RubyBlockLeadings
{
211 void Reset() { mStart
= mEnd
= 0; }
212 void Update(nscoord aStart
, nscoord aEnd
) {
213 mStart
= std::max(mStart
, aStart
);
214 mEnd
= std::max(mEnd
, aEnd
);
216 void Update(const RubyBlockLeadings
& aOther
) {
217 Update(aOther
.mStart
, aOther
.mEnd
);
221 } // namespace mozilla
223 #endif /* !defined(mozilla_RubyUtils_h_) */