Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 #include "CompositionStringSynthesizer.h"
7 #include "nsContentUtils.h"
8 #include "nsIDocShell.h"
9 #include "nsIFrame.h"
10 #include "nsIPresShell.h"
11 #include "nsIWidget.h"
12 #include "nsPIDOMWindow.h"
13 #include "nsView.h"
14 #include "mozilla/TextEvents.h"
16 namespace mozilla {
17 namespace dom {
19 NS_IMPL_ISUPPORTS(CompositionStringSynthesizer,
20 nsICompositionStringSynthesizer)
22 CompositionStringSynthesizer::CompositionStringSynthesizer(
23 nsPIDOMWindow* aWindow)
24 {
25 mWindow = do_GetWeakReference(aWindow);
26 mClauses = new TextRangeArray();
27 ClearInternal();
28 }
30 CompositionStringSynthesizer::~CompositionStringSynthesizer()
31 {
32 }
34 void
35 CompositionStringSynthesizer::ClearInternal()
36 {
37 mString.Truncate();
38 mClauses->Clear();
39 mCaret.mRangeType = 0;
40 }
42 nsIWidget*
43 CompositionStringSynthesizer::GetWidget()
44 {
45 nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
46 if (!window) {
47 return nullptr;
48 }
49 nsIDocShell *docShell = window->GetDocShell();
50 if (!docShell) {
51 return nullptr;
52 }
53 nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
54 if (!presShell) {
55 return nullptr;
56 }
57 nsIFrame* frame = presShell->GetRootFrame();
58 if (!frame) {
59 return nullptr;
60 }
61 return frame->GetView()->GetNearestWidget(nullptr);
62 }
64 NS_IMETHODIMP
65 CompositionStringSynthesizer::SetString(const nsAString& aString)
66 {
67 nsCOMPtr<nsIWidget> widget = GetWidget();
68 NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
70 mString = aString;
71 return NS_OK;
72 }
74 NS_IMETHODIMP
75 CompositionStringSynthesizer::AppendClause(uint32_t aLength,
76 uint32_t aAttribute)
77 {
78 nsCOMPtr<nsIWidget> widget = GetWidget();
79 NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
81 switch (aAttribute) {
82 case ATTR_RAWINPUT:
83 case ATTR_SELECTEDRAWTEXT:
84 case ATTR_CONVERTEDTEXT:
85 case ATTR_SELECTEDCONVERTEDTEXT: {
86 TextRange textRange;
87 textRange.mStartOffset =
88 mClauses->IsEmpty() ? 0 : mClauses->LastElement().mEndOffset;
89 textRange.mEndOffset = textRange.mStartOffset + aLength;
90 textRange.mRangeType = aAttribute;
91 mClauses->AppendElement(textRange);
92 return NS_OK;
93 }
94 default:
95 return NS_ERROR_INVALID_ARG;
96 }
97 }
99 NS_IMETHODIMP
100 CompositionStringSynthesizer::SetCaret(uint32_t aOffset, uint32_t aLength)
101 {
102 nsCOMPtr<nsIWidget> widget = GetWidget();
103 NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
105 mCaret.mStartOffset = aOffset;
106 mCaret.mEndOffset = mCaret.mStartOffset + aLength;
107 mCaret.mRangeType = NS_TEXTRANGE_CARETPOSITION;
108 return NS_OK;
109 }
111 NS_IMETHODIMP
112 CompositionStringSynthesizer::DispatchEvent(bool* aDefaultPrevented)
113 {
114 NS_ENSURE_ARG_POINTER(aDefaultPrevented);
115 nsCOMPtr<nsIWidget> widget = GetWidget();
116 NS_ENSURE_TRUE(widget && !widget->Destroyed(), NS_ERROR_NOT_AVAILABLE);
118 if (!nsContentUtils::IsCallerChrome()) {
119 return NS_ERROR_DOM_SECURITY_ERR;
120 }
122 if (!mClauses->IsEmpty() &&
123 mClauses->LastElement().mEndOffset != mString.Length()) {
124 NS_WARNING("Sum of length of the all clauses must be same as the string "
125 "length");
126 ClearInternal();
127 return NS_ERROR_ILLEGAL_VALUE;
128 }
129 if (mCaret.mRangeType == NS_TEXTRANGE_CARETPOSITION) {
130 if (mCaret.mEndOffset > mString.Length()) {
131 NS_WARNING("Caret position is out of the composition string");
132 ClearInternal();
133 return NS_ERROR_ILLEGAL_VALUE;
134 }
135 mClauses->AppendElement(mCaret);
136 }
138 WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget);
139 textEvent.time = PR_IntervalNow();
140 textEvent.theText = mString;
141 if (!mClauses->IsEmpty()) {
142 textEvent.mRanges = mClauses;
143 }
145 // XXX How should we set false for this on b2g?
146 textEvent.mFlags.mIsSynthesizedForTests = true;
148 nsEventStatus status = nsEventStatus_eIgnore;
149 nsresult rv = widget->DispatchEvent(&textEvent, status);
150 *aDefaultPrevented = (status == nsEventStatus_eConsumeNoDefault);
152 ClearInternal();
154 NS_ENSURE_SUCCESS(rv, rv);
156 return NS_OK;
157 }
159 } // namespace dom
160 } // namespace mozilla