Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 sw=2 et tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef mozilla_TextComposition_h |
michael@0 | 8 | #define mozilla_TextComposition_h |
michael@0 | 9 | |
michael@0 | 10 | #include "nsCOMPtr.h" |
michael@0 | 11 | #include "nsINode.h" |
michael@0 | 12 | #include "nsIWeakReference.h" |
michael@0 | 13 | #include "nsIWidget.h" |
michael@0 | 14 | #include "nsTArray.h" |
michael@0 | 15 | #include "nsThreadUtils.h" |
michael@0 | 16 | #include "nsPresContext.h" |
michael@0 | 17 | #include "mozilla/Attributes.h" |
michael@0 | 18 | #include "mozilla/EventForwards.h" |
michael@0 | 19 | #include "mozilla/TextRange.h" |
michael@0 | 20 | |
michael@0 | 21 | class nsIEditor; |
michael@0 | 22 | |
michael@0 | 23 | namespace mozilla { |
michael@0 | 24 | |
michael@0 | 25 | class EventDispatchingCallback; |
michael@0 | 26 | class IMEStateManager; |
michael@0 | 27 | |
michael@0 | 28 | /** |
michael@0 | 29 | * TextComposition represents a text composition. This class stores the |
michael@0 | 30 | * composition event target and its presContext. At dispatching the event via |
michael@0 | 31 | * this class, the instances use the stored event target. |
michael@0 | 32 | */ |
michael@0 | 33 | |
michael@0 | 34 | class TextComposition MOZ_FINAL |
michael@0 | 35 | { |
michael@0 | 36 | friend class IMEStateManager; |
michael@0 | 37 | |
michael@0 | 38 | NS_INLINE_DECL_REFCOUNTING(TextComposition) |
michael@0 | 39 | |
michael@0 | 40 | public: |
michael@0 | 41 | TextComposition(nsPresContext* aPresContext, |
michael@0 | 42 | nsINode* aNode, |
michael@0 | 43 | WidgetGUIEvent* aEvent); |
michael@0 | 44 | |
michael@0 | 45 | bool Destroyed() const { return !mPresContext; } |
michael@0 | 46 | nsPresContext* GetPresContext() const { return mPresContext; } |
michael@0 | 47 | nsINode* GetEventTargetNode() const { return mNode; } |
michael@0 | 48 | // The latest CompositionEvent.data value except compositionstart event. |
michael@0 | 49 | // This value is modified at dispatching compositionupdate. |
michael@0 | 50 | const nsString& LastData() const { return mLastData; } |
michael@0 | 51 | // The composition string which is already handled by the focused editor. |
michael@0 | 52 | // I.e., this value must be same as the composition string on the focused |
michael@0 | 53 | // editor. This value is modified at a call of EditorDidHandleTextEvent(). |
michael@0 | 54 | // Note that mString and mLastData are different between dispatcing |
michael@0 | 55 | // compositionupdate and text event handled by focused editor. |
michael@0 | 56 | const nsString& String() const { return mString; } |
michael@0 | 57 | // Returns the clauses and/or caret range of the composition string. |
michael@0 | 58 | // This is modified at a call of EditorWillHandleTextEvent(). |
michael@0 | 59 | // This may return null if there is no clauses and caret. |
michael@0 | 60 | // XXX We should return |const TextRangeArray*| here, but it causes compile |
michael@0 | 61 | // error due to inaccessible Release() method. |
michael@0 | 62 | TextRangeArray* GetRanges() const { return mRanges; } |
michael@0 | 63 | // Returns true if the composition is started with synthesized event which |
michael@0 | 64 | // came from nsDOMWindowUtils. |
michael@0 | 65 | bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; } |
michael@0 | 66 | |
michael@0 | 67 | bool MatchesNativeContext(nsIWidget* aWidget) const; |
michael@0 | 68 | |
michael@0 | 69 | /** |
michael@0 | 70 | * This is called when IMEStateManager stops managing the instance. |
michael@0 | 71 | */ |
michael@0 | 72 | void Destroy(); |
michael@0 | 73 | |
michael@0 | 74 | /** |
michael@0 | 75 | * SynthesizeCommit() dispatches compositionupdate, text and compositionend |
michael@0 | 76 | * events for emulating commit on the content. |
michael@0 | 77 | * |
michael@0 | 78 | * @param aDiscard true when committing with empty string. Otherwise, false. |
michael@0 | 79 | */ |
michael@0 | 80 | void SynthesizeCommit(bool aDiscard); |
michael@0 | 81 | |
michael@0 | 82 | /** |
michael@0 | 83 | * Send a notification to IME. It depends on the IME or platform spec what |
michael@0 | 84 | * will occur (or not occur). |
michael@0 | 85 | */ |
michael@0 | 86 | nsresult NotifyIME(widget::IMEMessage aMessage); |
michael@0 | 87 | |
michael@0 | 88 | /** |
michael@0 | 89 | * the offset of first selected clause or start of of compositon |
michael@0 | 90 | */ |
michael@0 | 91 | uint32_t OffsetOfTargetClause() const { return mCompositionTargetOffset; } |
michael@0 | 92 | |
michael@0 | 93 | /** |
michael@0 | 94 | * Returns true if there is non-empty composition string and it's not fixed. |
michael@0 | 95 | * Otherwise, false. |
michael@0 | 96 | */ |
michael@0 | 97 | bool IsComposing() const { return mIsComposing; } |
michael@0 | 98 | |
michael@0 | 99 | /** |
michael@0 | 100 | * Returns true while editor is handling an event which is modifying the |
michael@0 | 101 | * composition string. |
michael@0 | 102 | */ |
michael@0 | 103 | bool IsEditorHandlingEvent() const |
michael@0 | 104 | { |
michael@0 | 105 | return mIsEditorHandlingEvent; |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | /** |
michael@0 | 109 | * StartHandlingComposition() and EndHandlingComposition() are called by |
michael@0 | 110 | * editor when it holds a TextComposition instance and release it. |
michael@0 | 111 | */ |
michael@0 | 112 | void StartHandlingComposition(nsIEditor* aEditor); |
michael@0 | 113 | void EndHandlingComposition(nsIEditor* aEditor); |
michael@0 | 114 | |
michael@0 | 115 | /** |
michael@0 | 116 | * TextEventHandlingMarker class should be created at starting to handle text |
michael@0 | 117 | * event in focused editor. This calls EditorWillHandleTextEvent() and |
michael@0 | 118 | * EditorDidHandleTextEvent() automatically. |
michael@0 | 119 | */ |
michael@0 | 120 | class MOZ_STACK_CLASS TextEventHandlingMarker |
michael@0 | 121 | { |
michael@0 | 122 | public: |
michael@0 | 123 | TextEventHandlingMarker(TextComposition* aComposition, |
michael@0 | 124 | const WidgetTextEvent* aTextEvent) |
michael@0 | 125 | : mComposition(aComposition) |
michael@0 | 126 | { |
michael@0 | 127 | mComposition->EditorWillHandleTextEvent(aTextEvent); |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | ~TextEventHandlingMarker() |
michael@0 | 131 | { |
michael@0 | 132 | mComposition->EditorDidHandleTextEvent(); |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | private: |
michael@0 | 136 | nsRefPtr<TextComposition> mComposition; |
michael@0 | 137 | TextEventHandlingMarker(); |
michael@0 | 138 | TextEventHandlingMarker(const TextEventHandlingMarker& aOther); |
michael@0 | 139 | }; |
michael@0 | 140 | |
michael@0 | 141 | private: |
michael@0 | 142 | // Private destructor, to discourage deletion outside of Release(): |
michael@0 | 143 | ~TextComposition() |
michael@0 | 144 | { |
michael@0 | 145 | // WARNING: mPresContext may be destroying, so, be careful if you touch it. |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | // This class holds nsPresContext weak. This instance shouldn't block |
michael@0 | 149 | // destroying it. When the presContext is being destroyed, it's notified to |
michael@0 | 150 | // IMEStateManager::OnDestroyPresContext(), and then, it destroy |
michael@0 | 151 | // this instance. |
michael@0 | 152 | nsPresContext* mPresContext; |
michael@0 | 153 | nsCOMPtr<nsINode> mNode; |
michael@0 | 154 | |
michael@0 | 155 | // This is the clause and caret range information which is managed by |
michael@0 | 156 | // the focused editor. This may be null if there is no clauses or caret. |
michael@0 | 157 | nsRefPtr<TextRangeArray> mRanges; |
michael@0 | 158 | |
michael@0 | 159 | // mNativeContext stores a opaque pointer. This works as the "ID" for this |
michael@0 | 160 | // composition. Don't access the instance, it may not be available. |
michael@0 | 161 | void* mNativeContext; |
michael@0 | 162 | |
michael@0 | 163 | // mEditorWeak is a weak reference to the focused editor handling composition. |
michael@0 | 164 | nsWeakPtr mEditorWeak; |
michael@0 | 165 | |
michael@0 | 166 | // mLastData stores the data attribute of the latest composition event (except |
michael@0 | 167 | // the compositionstart event). |
michael@0 | 168 | nsString mLastData; |
michael@0 | 169 | |
michael@0 | 170 | // mString stores the composition text which has been handled by the focused |
michael@0 | 171 | // editor. |
michael@0 | 172 | nsString mString; |
michael@0 | 173 | |
michael@0 | 174 | // Offset of the composition string from start of the editor |
michael@0 | 175 | uint32_t mCompositionStartOffset; |
michael@0 | 176 | // Offset of the selected clause of the composition string from start of the |
michael@0 | 177 | // editor |
michael@0 | 178 | uint32_t mCompositionTargetOffset; |
michael@0 | 179 | |
michael@0 | 180 | // See the comment for IsSynthesizedForTests(). |
michael@0 | 181 | bool mIsSynthesizedForTests; |
michael@0 | 182 | |
michael@0 | 183 | // See the comment for IsComposing(). |
michael@0 | 184 | bool mIsComposing; |
michael@0 | 185 | |
michael@0 | 186 | // mIsEditorHandlingEvent is true while editor is modifying the composition |
michael@0 | 187 | // string. |
michael@0 | 188 | bool mIsEditorHandlingEvent; |
michael@0 | 189 | |
michael@0 | 190 | // Hide the default constructor and copy constructor. |
michael@0 | 191 | TextComposition() {} |
michael@0 | 192 | TextComposition(const TextComposition& aOther); |
michael@0 | 193 | |
michael@0 | 194 | /** |
michael@0 | 195 | * GetEditor() returns nsIEditor pointer of mEditorWeak. |
michael@0 | 196 | */ |
michael@0 | 197 | already_AddRefed<nsIEditor> GetEditor() const; |
michael@0 | 198 | |
michael@0 | 199 | /** |
michael@0 | 200 | * HasEditor() returns true if mEditorWeak holds nsIEditor instance which is |
michael@0 | 201 | * alive. Otherwise, false. |
michael@0 | 202 | */ |
michael@0 | 203 | bool HasEditor() const; |
michael@0 | 204 | |
michael@0 | 205 | /** |
michael@0 | 206 | * EditorWillHandleTextEvent() must be called before the focused editor |
michael@0 | 207 | * handles the text event. |
michael@0 | 208 | */ |
michael@0 | 209 | void EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent); |
michael@0 | 210 | |
michael@0 | 211 | /** |
michael@0 | 212 | * EditorDidHandleTextEvent() must be called after the focused editor handles |
michael@0 | 213 | * a text event. |
michael@0 | 214 | */ |
michael@0 | 215 | void EditorDidHandleTextEvent(); |
michael@0 | 216 | |
michael@0 | 217 | /** |
michael@0 | 218 | * DispatchEvent() dispatches the aEvent to the mContent synchronously. |
michael@0 | 219 | * The caller must ensure that it's safe to dispatch the event. |
michael@0 | 220 | */ |
michael@0 | 221 | void DispatchEvent(WidgetGUIEvent* aEvent, |
michael@0 | 222 | nsEventStatus* aStatus, |
michael@0 | 223 | EventDispatchingCallback* aCallBack); |
michael@0 | 224 | |
michael@0 | 225 | /** |
michael@0 | 226 | * Calculate composition offset then notify composition update to widget |
michael@0 | 227 | */ |
michael@0 | 228 | void NotityUpdateComposition(WidgetGUIEvent* aEvent); |
michael@0 | 229 | |
michael@0 | 230 | /** |
michael@0 | 231 | * CompositionEventDispatcher dispatches the specified composition (or text) |
michael@0 | 232 | * event. |
michael@0 | 233 | */ |
michael@0 | 234 | class CompositionEventDispatcher : public nsRunnable |
michael@0 | 235 | { |
michael@0 | 236 | public: |
michael@0 | 237 | CompositionEventDispatcher(nsPresContext* aPresContext, |
michael@0 | 238 | nsINode* aEventTarget, |
michael@0 | 239 | uint32_t aEventMessage, |
michael@0 | 240 | const nsAString& aData); |
michael@0 | 241 | NS_IMETHOD Run() MOZ_OVERRIDE; |
michael@0 | 242 | |
michael@0 | 243 | private: |
michael@0 | 244 | nsRefPtr<nsPresContext> mPresContext; |
michael@0 | 245 | nsCOMPtr<nsINode> mEventTarget; |
michael@0 | 246 | nsCOMPtr<nsIWidget> mWidget; |
michael@0 | 247 | uint32_t mEventMessage; |
michael@0 | 248 | nsString mData; |
michael@0 | 249 | |
michael@0 | 250 | CompositionEventDispatcher() {}; |
michael@0 | 251 | }; |
michael@0 | 252 | |
michael@0 | 253 | /** |
michael@0 | 254 | * DispatchCompositionEventRunnable() dispatches a composition or text event |
michael@0 | 255 | * to the content. Be aware, if you use this method, nsPresShellEventCB |
michael@0 | 256 | * isn't used. That means that nsIFrame::HandleEvent() is never called. |
michael@0 | 257 | * WARNING: The instance which is managed by IMEStateManager may be |
michael@0 | 258 | * destroyed by this method call. |
michael@0 | 259 | * |
michael@0 | 260 | * @param aEventMessage Must be one of composition event or text event. |
michael@0 | 261 | * @param aData Used for data value if aEventMessage is |
michael@0 | 262 | * NS_COMPOSITION_UPDATE or NS_COMPOSITION_END. |
michael@0 | 263 | * Used for theText value if aEventMessage is |
michael@0 | 264 | * NS_TEXT_TEXT. |
michael@0 | 265 | */ |
michael@0 | 266 | void DispatchCompositionEventRunnable(uint32_t aEventMessage, |
michael@0 | 267 | const nsAString& aData); |
michael@0 | 268 | }; |
michael@0 | 269 | |
michael@0 | 270 | /** |
michael@0 | 271 | * TextCompositionArray manages the instances of TextComposition class. |
michael@0 | 272 | * Managing with array is enough because only one composition is typically |
michael@0 | 273 | * there. Even if user switches native IME context, it's very rare that |
michael@0 | 274 | * second or more composition is started. |
michael@0 | 275 | * It's assumed that this is used by IMEStateManager for storing all active |
michael@0 | 276 | * compositions in the process. If the instance is it, each TextComposition |
michael@0 | 277 | * in the array can be destroyed by calling some methods of itself. |
michael@0 | 278 | */ |
michael@0 | 279 | |
michael@0 | 280 | class TextCompositionArray MOZ_FINAL : |
michael@0 | 281 | public nsAutoTArray<nsRefPtr<TextComposition>, 2> |
michael@0 | 282 | { |
michael@0 | 283 | public: |
michael@0 | 284 | index_type IndexOf(nsIWidget* aWidget); |
michael@0 | 285 | index_type IndexOf(nsPresContext* aPresContext); |
michael@0 | 286 | index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode); |
michael@0 | 287 | |
michael@0 | 288 | TextComposition* GetCompositionFor(nsIWidget* aWidget); |
michael@0 | 289 | TextComposition* GetCompositionFor(nsPresContext* aPresContext, |
michael@0 | 290 | nsINode* aNode); |
michael@0 | 291 | TextComposition* GetCompositionInContent(nsPresContext* aPresContext, |
michael@0 | 292 | nsIContent* aContent); |
michael@0 | 293 | }; |
michael@0 | 294 | |
michael@0 | 295 | } // namespace mozilla |
michael@0 | 296 | |
michael@0 | 297 | #endif // #ifndef mozilla_TextComposition_h |