/src/mozilla-central/layout/base/AccessibleCaret.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef AccessibleCaret_h__ |
8 | | #define AccessibleCaret_h__ |
9 | | |
10 | | #include "mozilla/Attributes.h" |
11 | | #include "mozilla/dom/AnonymousContent.h" |
12 | | #include "mozilla/dom/Element.h" |
13 | | #include "nsCOMPtr.h" |
14 | | #include "nsIDOMEventListener.h" |
15 | | #include "nsISupportsBase.h" |
16 | | #include "nsISupportsImpl.h" |
17 | | #include "nsLiteralString.h" |
18 | | #include "nsRect.h" |
19 | | #include "mozilla/RefPtr.h" |
20 | | #include "nsString.h" |
21 | | |
22 | | class nsIDocument; |
23 | | class nsIFrame; |
24 | | class nsIPresShell; |
25 | | struct nsPoint; |
26 | | |
27 | | namespace mozilla { |
28 | | |
29 | | namespace dom { |
30 | | class Event; |
31 | | } // namespace dom |
32 | | |
33 | | // ----------------------------------------------------------------------------- |
34 | | // Upon the creation of AccessibleCaret, it will insert DOM Element as an |
35 | | // anonymous content containing the caret image. The caret appearance and |
36 | | // position can be controlled by SetAppearance() and SetPosition(). |
37 | | // |
38 | | // All the rect or point are relative to root frame except being specified |
39 | | // explicitly. |
40 | | // |
41 | | // None of the methods in AccessibleCaret will flush layout or style. To ensure |
42 | | // that SetPosition() works correctly, the caller must make sure the layout is |
43 | | // up to date. |
44 | | // |
45 | | // Please see the wiki page for more information. |
46 | | // https://wiki.mozilla.org/AccessibleCaret |
47 | | // |
48 | | class AccessibleCaret |
49 | | { |
50 | | public: |
51 | | explicit AccessibleCaret(nsIPresShell* aPresShell); |
52 | | virtual ~AccessibleCaret(); |
53 | | |
54 | | // This enumeration representing the visibility and visual style of an |
55 | | // AccessibleCaret. |
56 | | // |
57 | | // Use SetAppearance() to change the appearance, and use GetAppearance() to |
58 | | // get the current appearance. |
59 | | enum class Appearance : uint8_t { |
60 | | // Do not display the caret at all. |
61 | | None, |
62 | | |
63 | | // Display the caret in default style. |
64 | | Normal, |
65 | | |
66 | | // The caret should be displayed logically but it is kept invisible to the |
67 | | // user. This enum is the only difference between "logically visible" and |
68 | | // "visually visible". It can be used for reasons such as: |
69 | | // 1. Out of scroll port. |
70 | | // 2. For UX requirement such as hide a caret in an empty text area. |
71 | | NormalNotShown, |
72 | | |
73 | | // Display the caret which is tilted to the left. |
74 | | Left, |
75 | | |
76 | | // Display the caret which is tilted to the right. |
77 | | Right |
78 | | }; |
79 | | |
80 | | friend std::ostream& operator<<(std::ostream& aStream, |
81 | | const Appearance& aAppearance); |
82 | | |
83 | | Appearance GetAppearance() const |
84 | 0 | { |
85 | 0 | return mAppearance; |
86 | 0 | } |
87 | | |
88 | | virtual void SetAppearance(Appearance aAppearance); |
89 | | |
90 | | // Return true if current appearance is either Normal, NormalNotShown, Left, |
91 | | // or Right. |
92 | | bool IsLogicallyVisible() const |
93 | 0 | { |
94 | 0 | return mAppearance != Appearance::None; |
95 | 0 | } |
96 | | |
97 | | // Return true if current appearance is either Normal, Left, or Right. |
98 | | bool IsVisuallyVisible() const |
99 | 0 | { |
100 | 0 | return (mAppearance != Appearance::None) && |
101 | 0 | (mAppearance != Appearance::NormalNotShown); |
102 | 0 | } |
103 | | |
104 | | // This enumeration representing the result returned by SetPosition(). |
105 | | enum class PositionChangedResult : uint8_t { |
106 | | // Position is not changed. |
107 | | NotChanged, |
108 | | |
109 | | // Position or zoom level is changed. |
110 | | Changed, |
111 | | |
112 | | // Position is out of scroll port. |
113 | | Invisible |
114 | | }; |
115 | | |
116 | | friend std::ostream& operator<<(std::ostream& aStream, |
117 | | const PositionChangedResult& aResult); |
118 | | |
119 | | virtual PositionChangedResult SetPosition(nsIFrame* aFrame, int32_t aOffset); |
120 | | |
121 | | // Does two AccessibleCarets overlap? |
122 | | bool Intersects(const AccessibleCaret& aCaret) const; |
123 | | |
124 | | // Is the point within the caret's rect? The point should be relative to root |
125 | | // frame. |
126 | | enum class TouchArea { |
127 | | Full, // Contains both text overlay and caret image. |
128 | | CaretImage |
129 | | }; |
130 | | bool Contains(const nsPoint& aPoint, TouchArea aTouchArea) const; |
131 | | |
132 | | // The geometry center of the imaginary caret (nsCaret) to which this |
133 | | // AccessibleCaret is attached. It is needed when dragging the caret. |
134 | | nsPoint LogicalPosition() const |
135 | 0 | { |
136 | 0 | return mImaginaryCaretRect.Center(); |
137 | 0 | } |
138 | | |
139 | | // Element for 'Intersects' test. This is the container of the caret image |
140 | | // and text-overlay elements. See CreateCaretElement() for the content |
141 | | // structure. |
142 | | dom::Element& CaretElement() const |
143 | 0 | { |
144 | 0 | return mCaretElementHolder->ContentNode(); |
145 | 0 | } |
146 | | |
147 | | // Ensures that the caret element is made "APZ aware" so that the APZ code |
148 | | // doesn't scroll the page when the user is trying to drag the caret. |
149 | | void EnsureApzAware(); |
150 | | |
151 | | protected: |
152 | | // Argument aRect should be relative to CustomContentContainerFrame(). |
153 | | void SetCaretElementStyle(const nsRect& aRect, float aZoomLevel); |
154 | | void SetTextOverlayElementStyle(const nsRect& aRect, float aZoomLevel); |
155 | | void SetCaretImageElementStyle(const nsRect& aRect, float aZoomLevel); |
156 | | |
157 | | // Get current zoom level. |
158 | | float GetZoomLevel(); |
159 | | |
160 | | // Element which contains the text overly for the 'Contains' test. |
161 | | dom::Element* TextOverlayElement() const |
162 | 0 | { |
163 | 0 | return mCaretElementHolder->GetElementById(sTextOverlayElementId); |
164 | 0 | } |
165 | | |
166 | | // Element which contains the caret image for 'Contains' test. |
167 | | dom::Element* CaretImageElement() const |
168 | 0 | { |
169 | 0 | return mCaretElementHolder->GetElementById(sCaretImageElementId); |
170 | 0 | } |
171 | | |
172 | | nsIFrame* RootFrame() const |
173 | 0 | { |
174 | 0 | return mPresShell->GetRootFrame(); |
175 | 0 | } |
176 | | |
177 | | nsIFrame* CustomContentContainerFrame() const; |
178 | | |
179 | | // Transform Appearance to CSS id used in ua.css. |
180 | | static nsAutoString AppearanceString(Appearance aAppearance); |
181 | | |
182 | | already_AddRefed<dom::Element> CreateCaretElement(nsIDocument* aDocument) const; |
183 | | |
184 | | // Inject caret element into custom content container. |
185 | | void InjectCaretElement(nsIDocument* aDocument); |
186 | | |
187 | | // Remove caret element from custom content container. |
188 | | void RemoveCaretElement(nsIDocument* aDocument); |
189 | | |
190 | | // The top-center of the imaginary caret to which this AccessibleCaret is |
191 | | // attached. |
192 | | static nsPoint CaretElementPosition(const nsRect& aRect) |
193 | 0 | { |
194 | 0 | return aRect.TopLeft() + nsPoint(aRect.width / 2, 0); |
195 | 0 | } |
196 | | |
197 | | class DummyTouchListener final : public nsIDOMEventListener |
198 | | { |
199 | | public: |
200 | | NS_DECL_ISUPPORTS |
201 | | NS_IMETHOD HandleEvent(mozilla::dom::Event* aEvent) override |
202 | 0 | { |
203 | 0 | return NS_OK; |
204 | 0 | } |
205 | | |
206 | | private: |
207 | 0 | virtual ~DummyTouchListener() {}; |
208 | | }; |
209 | | |
210 | | // Member variables |
211 | | Appearance mAppearance = Appearance::None; |
212 | | |
213 | | // AccessibleCaretManager owns us by a UniquePtr. When it's terminated by |
214 | | // AccessibleCaretEventHub::Terminate() which is called in |
215 | | // PresShell::Destroy(), it frees us automatically. No need to worry if we |
216 | | // outlive mPresShell. |
217 | | nsIPresShell* MOZ_NON_OWNING_REF const mPresShell = nullptr; |
218 | | |
219 | | RefPtr<dom::AnonymousContent> mCaretElementHolder; |
220 | | |
221 | | // mImaginaryCaretRect is relative to root frame. |
222 | | nsRect mImaginaryCaretRect; |
223 | | |
224 | | // Cache current zoom level to determine whether position is changed. |
225 | | float mZoomLevel = 0.0f; |
226 | | |
227 | | // A no-op touch-start listener which prevents APZ from panning when dragging |
228 | | // the caret. |
229 | | RefPtr<DummyTouchListener> mDummyTouchListener{new DummyTouchListener()}; |
230 | | |
231 | | // Static class variables |
232 | | static const nsLiteralString sTextOverlayElementId; |
233 | | static const nsLiteralString sCaretImageElementId; |
234 | | |
235 | | }; // class AccessibleCaret |
236 | | |
237 | | std::ostream& operator<<(std::ostream& aStream, |
238 | | const AccessibleCaret::Appearance& aAppearance); |
239 | | |
240 | | std::ostream& operator<<(std::ostream& aStream, |
241 | | const AccessibleCaret::PositionChangedResult& aResult); |
242 | | |
243 | | } // namespace mozilla |
244 | | |
245 | | #endif // AccessibleCaret_h__ |