Bug 1472338: part 1) Add Chrome tests for the async Clipboard API. r=NeilDeakin
[gecko.git] / widget / IMEData.cpp
blob85ba29a6bdc6172ceac6757fd579f80176525ec5
1 /* -*- Mode: C++; tab-width: 40; 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/. */
6 #include "IMEData.h"
8 #include <sstream>
10 #include "ContentData.h"
11 #include "gfxFontUtils.h"
12 #include "TextEvents.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/ToString.h"
16 #include "mozilla/WritingModes.h"
18 #include "nsPrintfCString.h"
19 #include "nsString.h"
21 namespace mozilla {
23 template PrintStringDetail::PrintStringDetail(
24 const Maybe<nsString>& aMaybeString, uint32_t aMaxLength);
26 template <typename StringType>
27 PrintStringDetail::PrintStringDetail(const Maybe<StringType>& aMaybeString,
28 uint32_t aMaxLength /* = UINT32_MAX */)
29 : PrintStringDetail(aMaybeString.refOr(EmptyString()), aMaxLength) {
30 if (aMaybeString.isNothing()) {
31 AssignASCII(ToString(aMaybeString).c_str());
35 PrintStringDetail::PrintStringDetail(const nsAString& aString,
36 uint32_t aMaxLength /* = UINT32_MAX */) {
37 Assign("\"");
38 const uint32_t kFirstHalf =
39 aString.Length() <= aMaxLength ? UINT32_MAX : (aMaxLength + 1) / 2;
40 const uint32_t kSecondHalf =
41 aString.Length() <= aMaxLength ? 0 : aMaxLength / 2;
42 for (uint32_t i = 0; i < aString.Length(); i++) {
43 if (i > 0) {
44 AppendLiteral(" ");
46 char32_t ch = aString.CharAt(i);
47 if (NS_IS_HIGH_SURROGATE(ch) && i + 1 < aString.Length() &&
48 NS_IS_LOW_SURROGATE(aString.CharAt(i + 1))) {
49 ch = SURROGATE_TO_UCS4(ch, aString.CharAt(i + 1));
51 Append(PrintCharData(ch));
52 if (i + 1 == kFirstHalf) {
53 AppendLiteral(" ...");
54 i = aString.Length() - kSecondHalf - 1;
55 if (NS_IS_LOW_SURROGATE(aString.CharAt(i)) &&
56 NS_IS_HIGH_SURROGATE(aString.CharAt(i - 1))) {
57 if (i - 1 <= kFirstHalf) {
58 i++;
59 } else {
60 i--;
63 } else if (!IS_IN_BMP(ch)) {
64 i++;
67 AppendLiteral("\" (Length()=");
68 AppendInt(static_cast<uint32_t>(aString.Length()));
69 AppendLiteral(")");
72 // static
73 nsCString PrintStringDetail::PrintCharData(char32_t aChar) {
74 switch (aChar) {
75 case 0x0000:
76 return "NULL (0x0000)"_ns;
77 case 0x0008:
78 return "BACKSPACE (0x0008)"_ns;
79 case 0x0009:
80 return "CHARACTER TABULATION (0x0009)"_ns;
81 case 0x000A:
82 return "LINE FEED (0x000A)"_ns;
83 case 0x000B:
84 return "LINE TABULATION (0x000B)"_ns;
85 case 0x000C:
86 return "FORM FEED (0x000C)"_ns;
87 case 0x000D:
88 return "CARRIAGE RETURN (0x000D)"_ns;
89 case 0x0018:
90 return "CANCEL (0x0018)"_ns;
91 case 0x001B:
92 return "ESCAPE (0x001B)"_ns;
93 case 0x0020:
94 return "SPACE (0x0020)"_ns;
95 case 0x007F:
96 return "DELETE (0x007F)"_ns;
97 case 0x00A0:
98 return "NO-BREAK SPACE (0x00A0)"_ns;
99 case 0x00AD:
100 return "SOFT HYPHEN (0x00AD)"_ns;
101 case 0x2000:
102 return "EN QUAD (0x2000)"_ns;
103 case 0x2001:
104 return "EM QUAD (0x2001)"_ns;
105 case 0x2002:
106 return "EN SPACE (0x2002)"_ns;
107 case 0x2003:
108 return "EM SPACE (0x2003)"_ns;
109 case 0x2004:
110 return "THREE-PER-EM SPACE (0x2004)"_ns;
111 case 0x2005:
112 return "FOUR-PER-EM SPACE (0x2005)"_ns;
113 case 0x2006:
114 return "SIX-PER-EM SPACE (0x2006)"_ns;
115 case 0x2007:
116 return "FIGURE SPACE (0x2007)"_ns;
117 case 0x2008:
118 return "PUNCTUATION SPACE (0x2008)"_ns;
119 case 0x2009:
120 return "THIN SPACE (0x2009)"_ns;
121 case 0x200A:
122 return "HAIR SPACE (0x200A)"_ns;
123 case 0x200B:
124 return "ZERO WIDTH SPACE (0x200B)"_ns;
125 case 0x200C:
126 return "ZERO WIDTH NON-JOINER (0x200C)"_ns;
127 case 0x200D:
128 return "ZERO WIDTH JOINER (0x200D)"_ns;
129 case 0x200E:
130 return "LEFT-TO-RIGHT MARK (0x200E)"_ns;
131 case 0x200F:
132 return "RIGHT-TO-LEFT MARK (0x200F)"_ns;
133 case 0x2029:
134 return "PARAGRAPH SEPARATOR (0x2029)"_ns;
135 case 0x202A:
136 return "LEFT-TO-RIGHT EMBEDDING (0x202A)"_ns;
137 case 0x202B:
138 return "RIGHT-TO-LEFT EMBEDDING (0x202B)"_ns;
139 case 0x202D:
140 return "LEFT-TO-RIGHT OVERRIDE (0x202D)"_ns;
141 case 0x202E:
142 return "RIGHT-TO-LEFT OVERRIDE (0x202E)"_ns;
143 case 0x202F:
144 return "NARROW NO-BREAK SPACE (0x202F)"_ns;
145 case 0x205F:
146 return "MEDIUM MATHEMATICAL SPACE (0x205F)"_ns;
147 case 0x2060:
148 return "WORD JOINER (0x2060)"_ns;
149 case 0x2066:
150 return "LEFT-TO-RIGHT ISOLATE (0x2066)"_ns;
151 case 0x2067:
152 return "RIGHT-TO-LEFT ISOLATE (0x2067)"_ns;
153 case 0x3000:
154 return "IDEOGRAPHIC SPACE (0x3000)"_ns;
155 case 0xFEFF:
156 return "ZERO WIDTH NO-BREAK SPACE (0xFEFF)"_ns;
157 default: {
158 if (aChar < ' ' || (aChar >= 0x80 && aChar < 0xA0)) {
159 return nsPrintfCString("Control (0x%04X)", aChar);
161 if (NS_IS_HIGH_SURROGATE(aChar)) {
162 return nsPrintfCString("High Surrogate (0x%04X)", aChar);
164 if (NS_IS_LOW_SURROGATE(aChar)) {
165 return nsPrintfCString("Low Surrogate (0x%04X)", aChar);
167 if (gfxFontUtils::IsVarSelector(aChar)) {
168 return IS_IN_BMP(aChar)
169 ? nsPrintfCString("Variant Selector (0x%04X)", aChar)
170 : nsPrintfCString("Variant Selector (0x%08X)", aChar);
172 nsAutoString utf16Str;
173 AppendUCS4ToUTF16(aChar, utf16Str);
174 return IS_IN_BMP(aChar)
175 ? nsPrintfCString("'%s' (0x%04X)",
176 NS_ConvertUTF16toUTF8(utf16Str).get(), aChar)
177 : nsPrintfCString("'%s' (0x%08X)",
178 NS_ConvertUTF16toUTF8(utf16Str).get(),
179 aChar);
184 namespace widget {
186 std::ostream& operator<<(std::ostream& aStream, const IMEEnabled& aEnabled) {
187 switch (aEnabled) {
188 case IMEEnabled::Disabled:
189 return aStream << "DISABLED";
190 case IMEEnabled::Enabled:
191 return aStream << "ENABLED";
192 case IMEEnabled::Password:
193 return aStream << "PASSWORD";
194 case IMEEnabled::Unknown:
195 return aStream << "illegal value";
197 MOZ_ASSERT_UNREACHABLE("Add a case to handle your new IMEEnabled value");
198 return aStream;
201 std::ostream& operator<<(std::ostream& aStream, const IMEState::Open& aOpen) {
202 switch (aOpen) {
203 case IMEState::DONT_CHANGE_OPEN_STATE:
204 aStream << "DONT_CHANGE_OPEN_STATE";
205 break;
206 case IMEState::OPEN:
207 aStream << "OPEN";
208 break;
209 case IMEState::CLOSED:
210 aStream << "CLOSED";
211 break;
212 default:
213 aStream << "illegal value";
214 break;
216 return aStream;
219 std::ostream& operator<<(std::ostream& aStream, const IMEState& aState) {
220 aStream << "{ mEnabled=" << aState.mEnabled << ", mOpen=" << aState.mOpen
221 << " }";
222 return aStream;
225 std::ostream& operator<<(std::ostream& aStream,
226 const InputContext::Origin& aOrigin) {
227 switch (aOrigin) {
228 case InputContext::ORIGIN_MAIN:
229 aStream << "ORIGIN_MAIN";
230 break;
231 case InputContext::ORIGIN_CONTENT:
232 aStream << "ORIGIN_CONTENT";
233 break;
234 default:
235 aStream << "illegal value";
236 break;
238 return aStream;
241 std::ostream& operator<<(std::ostream& aStream, const InputContext& aContext) {
242 aStream << "{ mIMEState=" << aContext.mIMEState
243 << ", mOrigin=" << aContext.mOrigin << ", mHTMLInputType=\""
244 << aContext.mHTMLInputType << "\", mHTMLInputInputmode=\""
245 << aContext.mHTMLInputInputmode << "\", mActionHint=\""
246 << aContext.mActionHint << "\", mAutocapitalize=\""
247 << aContext.mAutocapitalize << "\", mMayBeIMEUnaware="
248 << (aContext.mMayBeIMEUnaware ? "true" : "false")
249 << ", mIsPrivateBrowsing="
250 << (aContext.mInPrivateBrowsing ? "true" : "false") << " }";
251 return aStream;
254 std::ostream& operator<<(std::ostream& aStream,
255 const InputContextAction::Cause& aCause) {
256 switch (aCause) {
257 case InputContextAction::CAUSE_UNKNOWN:
258 aStream << "CAUSE_UNKNOWN";
259 break;
260 case InputContextAction::CAUSE_UNKNOWN_CHROME:
261 aStream << "CAUSE_UNKNOWN_CHROME";
262 break;
263 case InputContextAction::CAUSE_KEY:
264 aStream << "CAUSE_KEY";
265 break;
266 case InputContextAction::CAUSE_MOUSE:
267 aStream << "CAUSE_MOUSE";
268 break;
269 case InputContextAction::CAUSE_TOUCH:
270 aStream << "CAUSE_TOUCH";
271 break;
272 case InputContextAction::CAUSE_LONGPRESS:
273 aStream << "CAUSE_LONGPRESS";
274 break;
275 case InputContextAction::CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT:
276 aStream << "CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT";
277 break;
278 case InputContextAction::CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT:
279 aStream << "CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT";
280 break;
281 default:
282 aStream << "illegal value";
283 break;
285 return aStream;
288 std::ostream& operator<<(std::ostream& aStream,
289 const InputContextAction::FocusChange& aFocusChange) {
290 switch (aFocusChange) {
291 case InputContextAction::FOCUS_NOT_CHANGED:
292 aStream << "FOCUS_NOT_CHANGED";
293 break;
294 case InputContextAction::GOT_FOCUS:
295 aStream << "GOT_FOCUS";
296 break;
297 case InputContextAction::LOST_FOCUS:
298 aStream << "LOST_FOCUS";
299 break;
300 case InputContextAction::MENU_GOT_PSEUDO_FOCUS:
301 aStream << "MENU_GOT_PSEUDO_FOCUS";
302 break;
303 case InputContextAction::MENU_LOST_PSEUDO_FOCUS:
304 aStream << "MENU_LOST_PSEUDO_FOCUS";
305 break;
306 case InputContextAction::WIDGET_CREATED:
307 aStream << "WIDGET_CREATED";
308 break;
309 default:
310 aStream << "illegal value";
311 break;
313 return aStream;
316 std::ostream& operator<<(
317 std::ostream& aStream,
318 const IMENotification::SelectionChangeDataBase& aData) {
319 if (!aData.IsInitialized()) {
320 aStream << "{ IsInitialized()=false }";
321 return aStream;
323 if (!aData.HasRange()) {
324 aStream << "{ HasRange()=false }";
325 return aStream;
327 aStream << "{ mOffset=" << aData.mOffset;
328 if (aData.mString->Length() > 20) {
329 aStream << ", mString.Length()=" << aData.mString->Length();
330 } else {
331 aStream << ", mString=\"" << NS_ConvertUTF16toUTF8(*aData.mString)
332 << "\" (Length()=" << aData.mString->Length() << ")";
335 aStream << ", GetWritingMode()=" << aData.GetWritingMode()
336 << ", mReversed=" << (aData.mReversed ? "true" : "false")
337 << ", mCausedByComposition="
338 << (aData.mCausedByComposition ? "true" : "false")
339 << ", mCausedBySelectionEvent="
340 << (aData.mCausedBySelectionEvent ? "true" : "false")
341 << ", mOccurredDuringComposition="
342 << (aData.mOccurredDuringComposition ? "true" : "false") << " }";
343 return aStream;
346 std::ostream& operator<<(std::ostream& aStream,
347 const IMENotification::TextChangeDataBase& aData) {
348 if (!aData.IsValid()) {
349 aStream << "{ IsValid()=false }";
350 return aStream;
352 aStream << "{ mStartOffset=" << aData.mStartOffset
353 << ", mRemoveEndOffset=" << aData.mRemovedEndOffset
354 << ", mAddedEndOffset=" << aData.mAddedEndOffset
355 << ", mCausedOnlyByComposition="
356 << (aData.mCausedOnlyByComposition ? "true" : "false")
357 << ", mIncludingChangesDuringComposition="
358 << (aData.mIncludingChangesDuringComposition ? "true" : "false")
359 << ", mIncludingChangesWithoutComposition="
360 << (aData.mIncludingChangesWithoutComposition ? "true" : "false")
361 << " }";
362 return aStream;
365 /******************************************************************************
366 * IMENotification::SelectionChangeDataBase
367 ******************************************************************************/
369 void IMENotification::SelectionChangeDataBase::Assign(
370 const WidgetQueryContentEvent& aQuerySelectedTextEvent) {
371 MOZ_ASSERT(aQuerySelectedTextEvent.mMessage == eQuerySelectedText);
372 MOZ_ASSERT(aQuerySelectedTextEvent.Succeeded());
374 if (!(mIsInitialized = aQuerySelectedTextEvent.Succeeded())) {
375 ClearSelectionData();
376 return;
378 if ((mHasRange = aQuerySelectedTextEvent.FoundSelection())) {
379 mOffset = aQuerySelectedTextEvent.mReply->StartOffset();
380 *mString = aQuerySelectedTextEvent.mReply->DataRef();
381 mReversed = aQuerySelectedTextEvent.mReply->mReversed;
382 SetWritingMode(aQuerySelectedTextEvent.mReply->WritingModeRef());
383 } else {
384 mOffset = UINT32_MAX;
385 mString->Truncate();
386 mReversed = false;
387 // Let's keep the writing mode for avoiding temporarily changing the
388 // writing mode at no selection range.
392 void IMENotification::SelectionChangeDataBase::SetWritingMode(
393 const WritingMode& aWritingMode) {
394 mWritingModeBits = aWritingMode.GetBits();
397 WritingMode IMENotification::SelectionChangeDataBase::GetWritingMode() const {
398 return WritingMode(mWritingModeBits);
401 bool IMENotification::SelectionChangeDataBase::EqualsRange(
402 const ContentSelection& aContentSelection) const {
403 if (aContentSelection.HasRange() != HasRange()) {
404 return false;
406 if (!HasRange()) {
407 return true;
409 return mOffset == aContentSelection.OffsetAndDataRef().StartOffset() &&
410 *mString == aContentSelection.OffsetAndDataRef().DataRef();
413 bool IMENotification::SelectionChangeDataBase::EqualsRangeAndWritingMode(
414 const ContentSelection& aContentSelection) const {
415 return EqualsRange(aContentSelection) &&
416 mWritingModeBits == aContentSelection.WritingModeRef().GetBits();
419 } // namespace widget
420 } // namespace mozilla