File: TSFTextStoreBase.h

package info (click to toggle)
firefox 146.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,653,260 kB
  • sloc: cpp: 7,587,892; javascript: 6,509,455; ansic: 3,755,295; python: 1,410,813; xml: 629,201; asm: 438,677; java: 186,096; sh: 62,697; makefile: 18,086; objc: 13,087; perl: 12,811; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; php: 436; lisp: 258; awk: 247; sql: 66; sed: 54; csh: 10; exp: 6
file content (259 lines) | stat: -rw-r--r-- 10,724 bytes parent folder | download | duplicates (13)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef TSFTextStoreBase_h
#define TSFTextStoreBase_h

#include "nsIWidget.h"
#include "nsWindow.h"
#include "TSFUtils.h"  // for inputscope.h with the hack for MinGW
#include "WinUtils.h"
#include "WritingModes.h"

#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/WritingModes.h"
#include "mozilla/widget/IMEData.h"

#include <msctf.h>
#include <textstor.h>

struct ITfDocumentMgr;
class nsWindow;

namespace mozilla::widget {

class TSFTextStoreBase : public ITextStoreACP {
 protected:
  using SelectionChangeDataBase = IMENotification::SelectionChangeDataBase;
  using SelectionChangeData = IMENotification::SelectionChangeData;
  using TextChangeDataBase = IMENotification::TextChangeDataBase;
  using TextChangeData = IMENotification::TextChangeData;

 public: /*IUnknown*/
  STDMETHODIMP QueryInterface(REFIID, void**);

  NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(TSFTextStoreBase)

 public: /*ITextStoreACP*/
  STDMETHODIMP AdviseSink(REFIID, IUnknown*, DWORD);
  STDMETHODIMP UnadviseSink(IUnknown*);
  STDMETHODIMP RequestLock(DWORD, HRESULT*);
  STDMETHODIMP GetStatus(TS_STATUS*);
  STDMETHODIMP QueryInsert(LONG, LONG, ULONG, LONG*, LONG*);
  STDMETHODIMP GetSelection(ULONG, ULONG, TS_SELECTION_ACP*, ULONG*);
  STDMETHODIMP SetSelection(ULONG, const TS_SELECTION_ACP*);
  STDMETHODIMP GetText(LONG, LONG, WCHAR*, ULONG, ULONG*, TS_RUNINFO*, ULONG,
                       ULONG*, LONG*);
  STDMETHODIMP SetText(DWORD, LONG, LONG, const WCHAR*, ULONG, TS_TEXTCHANGE*);
  STDMETHODIMP GetFormattedText(LONG, LONG, IDataObject**);
  STDMETHODIMP GetEmbedded(LONG, REFGUID, REFIID, IUnknown**);
  STDMETHODIMP QueryInsertEmbedded(const GUID*, const FORMATETC*, BOOL*);
  STDMETHODIMP InsertEmbedded(DWORD, LONG, LONG, IDataObject*, TS_TEXTCHANGE*);
  STDMETHODIMP RequestAttrsTransitioningAtPosition(LONG, ULONG,
                                                   const TS_ATTRID*, DWORD);
  STDMETHODIMP FindNextAttrTransition(LONG, LONG, ULONG, const TS_ATTRID*,
                                      DWORD, LONG*, BOOL*, LONG*);
  STDMETHODIMP GetEndACP(LONG*);
  STDMETHODIMP GetActiveView(TsViewCookie*);
  STDMETHODIMP GetACPFromPoint(TsViewCookie, const POINT*, DWORD, LONG*);
  STDMETHODIMP GetTextExt(TsViewCookie, LONG, LONG, RECT*, BOOL*);
  STDMETHODIMP GetScreenExt(TsViewCookie, RECT*);
  STDMETHODIMP GetWnd(TsViewCookie, HWND*);
  STDMETHODIMP InsertTextAtSelection(DWORD, const WCHAR*, ULONG, LONG*, LONG*,
                                     TS_TEXTCHANGE*);
  STDMETHODIMP InsertEmbeddedAtSelection(DWORD, IDataObject*, LONG*, LONG*,
                                         TS_TEXTCHANGE*);

 public:
  [[nodiscard]] bool MaybeHasFocus() const { return mContext; }

  /**
   * Return true if this is for editable content, i.e., supporting retrieving
   * and modifying the content.  I.e., when this is a TSFTextStore instance,
   * returns true.  Otherwise, this is a TSFEmptyTextStoreInstance, returns
   * false.
   */
  [[nodiscard]] bool IsEditable() const {
    return static_cast<bool>(mIsEditable);
  }

  [[nodiscard]] ITfDocumentMgr* GetDocumentMgr() const { return mDocumentMgr; }
  [[nodiscard]] ITfContext* GetContext() const { return mContext; }
  [[nodiscard]] nsWindow* GetWindow() const { return mWidget; }

  [[nodiscard]] virtual IMENotificationRequests GetIMENotificationRequests()
      const = 0;

  virtual void Destroy() = 0;

  static void SetInputContext(nsWindow* aWindow, const InputContext& aContext,
                              const InputContextAction& aAction);

 protected:
  enum class Editable : bool { No, Yes };
  friend inline std::ostream& operator<<(std::ostream& aStream,
                                         const Editable& aEditable) {
    return aStream << (static_cast<bool>(aEditable) ? "Editable::Yes"
                                                    : "Editable::No");
  };
  explicit TSFTextStoreBase(Editable aIsEditable) : mIsEditable(aIsEditable) {}
  virtual ~TSFTextStoreBase() = default;

  [[nodiscard]] bool InitBase(nsWindow* aWidget, const InputContext& aContext);

  [[nodiscard]] static bool IsReadLock(DWORD aLock) {
    return (TS_LF_READ == (aLock & TS_LF_READ));
  }
  [[nodiscard]] static bool IsReadWriteLock(DWORD aLock) {
    return (TS_LF_READWRITE == (aLock & TS_LF_READWRITE));
  }
  [[nodiscard]] bool IsReadLocked() const { return IsReadLock(mLock); }
  [[nodiscard]] bool IsReadWriteLocked() const {
    return IsReadWriteLock(mLock);
  }

  // This is called immediately after a call of OnLockGranted() of mSink.
  // Note that mLock isn't cleared yet when this is called.
  virtual void DidLockGranted() {}

  using AttrIndices = EnumSet<TSFUtils::AttrIndex>;
  constexpr static auto NothingChanged = AttrIndices{};
  constexpr static auto OnlyURLChanged =
      AttrIndices{TSFUtils::AttrIndex::DocumentURL};
  constexpr static auto OnlyInputScopeChanged =
      AttrIndices{TSFUtils::AttrIndex::InputScope};
  constexpr static auto URLAndInputScopeChanged = AttrIndices{
      TSFUtils::AttrIndex::DocumentURL, TSFUtils::AttrIndex::InputScope};
  /**
   * Called when either the URL or the input scope is changed.
   */
  void NotifyTSFOfInputContextChange(AttrIndices aAttrIndices);

  [[nodiscard]] bool GetScreenExtInternal(RECT& aScreenExt);

  [[nodiscard]] virtual Maybe<WritingMode> GetWritingMode() {
    return Nothing();
  }

  // DispatchEvent() dispatches the event and if it may not be handled
  // synchronously, this makes the instance not notify TSF of pending
  // notifications until next notification from content.
  void DispatchEvent(WidgetGUIEvent& aEvent);

  void SetInputScope(const nsString& aHTMLInputType,
                     const nsString& aHTMLInputMode);

  /**
   * Return URL which can be exposed to TSF.  Use ::SysFreeString() to delete
   * the result if you use it by yourself.
   */
  BSTR GetExposingURL() const;

  /**
   * Debug utility method to print the result of GetExposingURL().
   */
  void PrintExposingURL(const char* aPrefix) const;

  HRESULT HandleRequestAttrs(DWORD aFlags, ULONG aFilterCount,
                             const TS_ATTRID* aFilterAttrs,
                             int32_t aNumOfSupportedAttrs);
  HRESULT RetrieveRequestedAttrsInternal(ULONG ulCount, TS_ATTRVAL* paAttrVals,
                                         ULONG* pcFetched,
                                         int32_t aNumOfSupportedAttrs);

  /**
   * IsHandlingCompositionInParent() returns true if eCompositionStart is
   * dispatched, but eCompositionCommit(AsIs) is not dispatched.  This means
   * that if composition is handled in a content process, this status indicates
   * whether ContentCacheInParent has composition or not.  On the other hand,
   * if it's handled in the chrome process, this is exactly same as
   * IsHandlingCompositionInContent().
   */
  [[nodiscard]] bool IsHandlingCompositionInParent() const {
    return mDispatcher && mDispatcher->IsComposing();
  }

  /**
   * IsHandlingCompositionInContent() returns true if there is a composition in
   * the focused editor which may be in a content process.
   */
  [[nodiscard]] bool IsHandlingCompositionInContent() const {
    return mDispatcher && mDispatcher->IsHandlingComposition();
  }

  /**
   * Return error if editable state does not match with this instance.
   * Otherwise, updates mDocumentURL and mInPrivateBrowsing and notify TSF of
   * the changes.
   */
  nsresult UpdateDocumentURLAndBrowsingMode(nsWindow* aWindow,
                                            const InputContext& aContext);

  // Holds the pointer to our current win32 widget
  RefPtr<nsWindow> mWidget;
  // mDispatcher is a helper class to dispatch composition events.
  RefPtr<TextEventDispatcher> mDispatcher;
  // Document manager for the currently focused editor
  RefPtr<ITfDocumentMgr> mDocumentMgr;
  // Edit cookie associated with the current editing context
  DWORD mEditCookie = 0;
  // Editing context at the bottom of mDocumentMgr's context stack
  RefPtr<ITfContext> mContext;
  // Currently installed notification sink
  RefPtr<ITextStoreACPSink> mSink;
  // TS_AS_* mask of what events to notify
  DWORD mSinkMask = 0;
  // 0 if not locked, otherwise TS_LF_* indicating the current lock
  DWORD mLock = 0;
  // 0 if no lock is queued, otherwise TS_LF_* indicating the queue lock
  DWORD mLockQueued = 0;

  // The input scopes for this context, defaults to IS_DEFAULT.
  nsTArray<InputScope> mInputScopes;

  // The URL cache of the focused document.
  nsString mDocumentURL;

  bool mRequestedAttrs[TSFUtils::NUM_OF_SUPPORTED_ATTRS] = {false};

  bool mRequestedAttrValues = false;

  // Before calling ITextStoreACPSink::OnLayoutChange() and
  // ITfContextOwnerServices::OnLayoutChange(), mWaitingQueryLayout is set to
  // true.  This is set to  false when GetTextExt() or GetACPFromPoint() is
  // called.
  bool mWaitingQueryLayout = false;
  // During the document is locked, we shouldn't destroy the instance.
  // If this is true, the instance will be destroyed after unlocked.
  bool mPendingDestroy = false;
  // While the instance is initializing content/selection cache, another
  // initialization shouldn't run recursively.  Therefore, while the
  // initialization is running, this is set to true.  Use AutoNotifyingTSFBatch
  // to set this.
  bool mDeferNotifyingTSF = false;
  // While the instance is dispatching events, the event may not be handled
  // synchronously when remote content has focus.  In the case, we cannot
  // return the latest layout/content information to TSF/TIP until we get next
  // update notification from ContentCacheInParent.  For preventing TSF/TIP
  // retrieves the latest content/layout information while it becomes available,
  // we should put off notifying TSF of any updates.
  bool mDeferNotifyingTSFUntilNextUpdate = false;
  // Immediately after a call of Destroy(), mDestroyed becomes true.  If this
  // is true, the instance shouldn't grant any requests from the TIP anymore.
  bool mDestroyed = false;
  // While the instance is being destroyed, this is set to true for avoiding
  // recursive Destroy() calls.
  bool mBeingDestroyed = false;
  // Whether we're in the private browsing mode.
  bool mInPrivateBrowsing = true;
  // Whether this is for editable content or not.
  Editable mIsEditable;
};

}  // namespace mozilla::widget

#endif  // #ifndef TSFTextStoreBase_h