Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef mozilla_TextRage_h_
7 : #define mozilla_TextRage_h_
8 :
9 : #include <stdint.h>
10 :
11 : #include "mozilla/EventForwards.h"
12 :
13 : #include "nsColor.h"
14 : #include "nsISelectionController.h"
15 : #include "nsITextInputProcessor.h"
16 : #include "nsStyleConsts.h"
17 : #include "nsTArray.h"
18 :
19 : namespace mozilla {
20 :
21 : /******************************************************************************
22 : * mozilla::TextRangeStyle
23 : ******************************************************************************/
24 :
25 : struct TextRangeStyle
26 : {
27 : enum
28 : {
29 : LINESTYLE_NONE = NS_STYLE_TEXT_DECORATION_STYLE_NONE,
30 : LINESTYLE_SOLID = NS_STYLE_TEXT_DECORATION_STYLE_SOLID,
31 : LINESTYLE_DOTTED = NS_STYLE_TEXT_DECORATION_STYLE_DOTTED,
32 : LINESTYLE_DASHED = NS_STYLE_TEXT_DECORATION_STYLE_DASHED,
33 : LINESTYLE_DOUBLE = NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE,
34 : LINESTYLE_WAVY = NS_STYLE_TEXT_DECORATION_STYLE_WAVY
35 : };
36 :
37 : enum
38 : {
39 : DEFINED_NONE = 0x00,
40 : DEFINED_LINESTYLE = 0x01,
41 : DEFINED_FOREGROUND_COLOR = 0x02,
42 : DEFINED_BACKGROUND_COLOR = 0x04,
43 : DEFINED_UNDERLINE_COLOR = 0x08
44 : };
45 :
46 : // Initialize all members, because TextRange instances may be compared by
47 : // memcomp.
48 46 : TextRangeStyle()
49 46 : {
50 46 : Clear();
51 46 : }
52 :
53 46 : void Clear()
54 : {
55 46 : mDefinedStyles = DEFINED_NONE;
56 46 : mLineStyle = LINESTYLE_NONE;
57 46 : mIsBoldLine = false;
58 46 : mForegroundColor = mBackgroundColor = mUnderlineColor = NS_RGBA(0, 0, 0, 0);
59 46 : }
60 :
61 0 : bool IsDefined() const { return mDefinedStyles != DEFINED_NONE; }
62 :
63 0 : bool IsLineStyleDefined() const
64 : {
65 0 : return (mDefinedStyles & DEFINED_LINESTYLE) != 0;
66 : }
67 :
68 0 : bool IsForegroundColorDefined() const
69 : {
70 0 : return (mDefinedStyles & DEFINED_FOREGROUND_COLOR) != 0;
71 : }
72 :
73 0 : bool IsBackgroundColorDefined() const
74 : {
75 0 : return (mDefinedStyles & DEFINED_BACKGROUND_COLOR) != 0;
76 : }
77 :
78 0 : bool IsUnderlineColorDefined() const
79 : {
80 0 : return (mDefinedStyles & DEFINED_UNDERLINE_COLOR) != 0;
81 : }
82 :
83 : bool IsNoChangeStyle() const
84 : {
85 : return !IsForegroundColorDefined() && !IsBackgroundColorDefined() &&
86 : IsLineStyleDefined() && mLineStyle == LINESTYLE_NONE;
87 : }
88 :
89 0 : bool Equals(const TextRangeStyle& aOther) const
90 : {
91 0 : if (mDefinedStyles != aOther.mDefinedStyles)
92 0 : return false;
93 0 : if (IsLineStyleDefined() && (mLineStyle != aOther.mLineStyle ||
94 0 : !mIsBoldLine != !aOther.mIsBoldLine))
95 0 : return false;
96 0 : if (IsForegroundColorDefined() &&
97 0 : (mForegroundColor != aOther.mForegroundColor))
98 0 : return false;
99 0 : if (IsBackgroundColorDefined() &&
100 0 : (mBackgroundColor != aOther.mBackgroundColor))
101 0 : return false;
102 0 : if (IsUnderlineColorDefined() &&
103 0 : (mUnderlineColor != aOther.mUnderlineColor))
104 0 : return false;
105 0 : return true;
106 : }
107 :
108 : bool operator !=(const TextRangeStyle &aOther) const
109 : {
110 : return !Equals(aOther);
111 : }
112 :
113 0 : bool operator ==(const TextRangeStyle &aOther) const
114 : {
115 0 : return Equals(aOther);
116 : }
117 :
118 : uint8_t mDefinedStyles;
119 : uint8_t mLineStyle; // DEFINED_LINESTYLE
120 :
121 : bool mIsBoldLine; // DEFINED_LINESTYLE
122 :
123 : nscolor mForegroundColor; // DEFINED_FOREGROUND_COLOR
124 : nscolor mBackgroundColor; // DEFINED_BACKGROUND_COLOR
125 : nscolor mUnderlineColor; // DEFINED_UNDERLINE_COLOR
126 : };
127 :
128 : /******************************************************************************
129 : * mozilla::TextRange
130 : ******************************************************************************/
131 :
132 : enum class TextRangeType : RawTextRangeType
133 : {
134 : eUninitialized = 0x00,
135 : eCaret = 0x01,
136 : eRawClause = nsITextInputProcessor::ATTR_RAW_CLAUSE,
137 : eSelectedRawClause = nsITextInputProcessor::ATTR_SELECTED_RAW_CLAUSE,
138 : eConvertedClause = nsITextInputProcessor::ATTR_CONVERTED_CLAUSE,
139 : eSelectedClause = nsITextInputProcessor::ATTR_SELECTED_CLAUSE
140 : };
141 :
142 : bool IsValidRawTextRangeValue(RawTextRangeType aRawTextRangeValue);
143 : RawTextRangeType ToRawTextRangeType(TextRangeType aTextRangeType);
144 : TextRangeType ToTextRangeType(RawTextRangeType aRawTextRangeType);
145 : const char* ToChar(TextRangeType aTextRangeType);
146 : SelectionType ToSelectionType(TextRangeType aTextRangeType);
147 :
148 0 : inline RawSelectionType ToRawSelectionType(TextRangeType aTextRangeType)
149 : {
150 0 : return ToRawSelectionType(ToSelectionType(aTextRangeType));
151 : }
152 :
153 : struct TextRange
154 : {
155 0 : TextRange()
156 0 : : mStartOffset(0)
157 : , mEndOffset(0)
158 0 : , mRangeType(TextRangeType::eUninitialized)
159 : {
160 0 : }
161 :
162 : uint32_t mStartOffset;
163 : // XXX Storing end offset makes the initializing code very complicated.
164 : // We should replace it with mLength.
165 : uint32_t mEndOffset;
166 :
167 : TextRangeStyle mRangeStyle;
168 :
169 : TextRangeType mRangeType;
170 :
171 0 : uint32_t Length() const { return mEndOffset - mStartOffset; }
172 :
173 0 : bool IsClause() const
174 : {
175 0 : return mRangeType != TextRangeType::eCaret;
176 : }
177 :
178 0 : bool Equals(const TextRange& aOther) const
179 : {
180 0 : return mStartOffset == aOther.mStartOffset &&
181 0 : mEndOffset == aOther.mEndOffset &&
182 0 : mRangeType == aOther.mRangeType &&
183 0 : mRangeStyle == aOther.mRangeStyle;
184 : }
185 :
186 0 : void RemoveCharacter(uint32_t aOffset)
187 : {
188 0 : if (mStartOffset > aOffset) {
189 0 : --mStartOffset;
190 0 : --mEndOffset;
191 0 : } else if (mEndOffset > aOffset) {
192 0 : --mEndOffset;
193 : }
194 0 : }
195 : };
196 :
197 : /******************************************************************************
198 : * mozilla::TextRangeArray
199 : ******************************************************************************/
200 0 : class TextRangeArray final : public AutoTArray<TextRange, 10>
201 : {
202 : friend class WidgetCompositionEvent;
203 :
204 0 : ~TextRangeArray() {}
205 :
206 0 : NS_INLINE_DECL_REFCOUNTING(TextRangeArray)
207 :
208 0 : const TextRange* GetTargetClause() const
209 : {
210 0 : for (uint32_t i = 0; i < Length(); ++i) {
211 0 : const TextRange& range = ElementAt(i);
212 0 : if (range.mRangeType == TextRangeType::eSelectedRawClause ||
213 0 : range.mRangeType == TextRangeType::eSelectedClause) {
214 0 : return ⦥
215 : }
216 : }
217 0 : return nullptr;
218 : }
219 :
220 : // Returns target clause offset. If there are selected clauses, this returns
221 : // the first selected clause offset. Otherwise, 0.
222 0 : uint32_t TargetClauseOffset() const
223 : {
224 0 : const TextRange* range = GetTargetClause();
225 0 : return range ? range->mStartOffset : 0;
226 : }
227 :
228 : // Returns target clause length. If there are selected clauses, this returns
229 : // the first selected clause length. Otherwise, UINT32_MAX.
230 0 : uint32_t TargetClauseLength() const
231 : {
232 0 : const TextRange* range = GetTargetClause();
233 0 : return range ? range->Length() : UINT32_MAX;
234 : }
235 :
236 : public:
237 0 : bool IsComposing() const
238 : {
239 0 : for (uint32_t i = 0; i < Length(); ++i) {
240 0 : if (ElementAt(i).IsClause()) {
241 0 : return true;
242 : }
243 : }
244 0 : return false;
245 : }
246 :
247 0 : bool Equals(const TextRangeArray& aOther) const
248 : {
249 0 : size_t len = Length();
250 0 : if (len != aOther.Length()) {
251 0 : return false;
252 : }
253 0 : for (size_t i = 0; i < len; i++) {
254 0 : if (!ElementAt(i).Equals(aOther.ElementAt(i))) {
255 0 : return false;
256 : }
257 : }
258 0 : return true;
259 : }
260 :
261 0 : void RemoveCharacter(uint32_t aOffset)
262 : {
263 0 : for (size_t i = 0, len = Length(); i < len; i++) {
264 0 : ElementAt(i).RemoveCharacter(aOffset);
265 : }
266 0 : }
267 :
268 : bool HasCaret() const
269 : {
270 : for (const TextRange& range : *this) {
271 : if (range.mRangeType == TextRangeType::eCaret) {
272 : return true;
273 : }
274 : }
275 : return false;
276 : }
277 :
278 0 : bool HasClauses() const
279 : {
280 0 : for (const TextRange& range : *this) {
281 0 : if (range.IsClause()) {
282 0 : return true;
283 : }
284 : }
285 0 : return false;
286 : }
287 :
288 : uint32_t GetCaretPosition() const
289 : {
290 : for (const TextRange& range : *this) {
291 : if (range.mRangeType == TextRangeType::eCaret) {
292 : return range.mStartOffset;
293 : }
294 : }
295 : return UINT32_MAX;
296 : }
297 :
298 0 : const TextRange* GetFirstClause() const
299 : {
300 0 : for (const TextRange& range : *this) {
301 : // Look for the range of a clause whose start offset is 0 because the
302 : // first clause's start offset is always 0.
303 0 : if (range.IsClause() && !range.mStartOffset) {
304 0 : return ⦥
305 : }
306 : }
307 0 : MOZ_ASSERT(!HasClauses());
308 0 : return nullptr;
309 : }
310 : };
311 :
312 : } // namespace mozilla
313 :
314 : #endif // mozilla_TextRage_h_
|