Bug 1776056 - Switch to the tab an animation is running and make sure the animation...
[gecko.git] / layout / base / AccessibleCaret.h
blob979a5286399764b4291fd5918983efa59598444c
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/. */
7 #ifndef AccessibleCaret_h__
8 #define AccessibleCaret_h__
10 #include "mozilla/Attributes.h"
11 #include "mozilla/dom/AnonymousContent.h"
12 #include "nsCOMPtr.h"
13 #include "nsIDOMEventListener.h"
14 #include "nsIFrame.h" // for WeakFrame only
15 #include "nsISupports.h"
16 #include "nsISupportsImpl.h"
17 #include "nsLiteralString.h"
18 #include "nsRect.h"
19 #include "mozilla/RefPtr.h"
20 #include "nsString.h"
22 class nsIFrame;
23 struct nsPoint;
25 namespace mozilla {
26 class PresShell;
27 namespace dom {
28 class Element;
29 class Event;
30 } // namespace dom
32 // -----------------------------------------------------------------------------
33 // Upon the creation of AccessibleCaret, it will insert DOM Element as an
34 // anonymous content containing the caret image. The caret appearance and
35 // position can be controlled by SetAppearance() and SetPosition().
37 // All the rect or point are relative to root frame except being specified
38 // explicitly.
40 // None of the methods in AccessibleCaret will flush layout or style. To ensure
41 // that SetPosition() works correctly, the caller must make sure the layout is
42 // up to date.
44 // Please see the wiki page for more information.
45 // https://wiki.mozilla.org/AccessibleCaret
47 class AccessibleCaret {
48 public:
49 explicit AccessibleCaret(PresShell* aPresShell);
50 virtual ~AccessibleCaret();
52 // This enumeration representing the visibility and visual style of an
53 // AccessibleCaret.
55 // Use SetAppearance() to change the appearance, and use GetAppearance() to
56 // get the current appearance.
57 enum class Appearance : uint8_t {
58 // Do not display the caret at all.
59 None,
61 // Display the caret in default style.
62 Normal,
64 // The caret should be displayed logically but it is kept invisible to the
65 // user. This enum is the only difference between "logically visible" and
66 // "visually visible". It can be used for reasons such as:
67 // 1. Out of scroll port.
68 // 2. For UX requirement such as hide a caret in an empty text area.
69 NormalNotShown,
71 // Display the caret which is tilted to the left.
72 Left,
74 // Display the caret which is tilted to the right.
75 Right
78 friend std::ostream& operator<<(std::ostream& aStream,
79 const Appearance& aAppearance);
81 Appearance GetAppearance() const { return mAppearance; }
83 virtual void SetAppearance(Appearance aAppearance);
85 // Return true if current appearance is either Normal, NormalNotShown, Left,
86 // or Right.
87 bool IsLogicallyVisible() const { return mAppearance != Appearance::None; }
89 // Return true if current appearance is either Normal, Left, or Right.
90 bool IsVisuallyVisible() const {
91 return (mAppearance != Appearance::None) &&
92 (mAppearance != Appearance::NormalNotShown);
95 // This enum represents the result returned by SetPosition().
96 enum class PositionChangedResult : uint8_t {
97 // Both position and the zoom level are not changed.
98 NotChanged,
100 // The position is changed. (The zoom level may or may not be changed.)
101 Position,
103 // Only the zoom level is changed. The position is *not* changed.
104 Zoom,
106 // The position is out of scroll port.
107 Invisible
110 friend std::ostream& operator<<(std::ostream& aStream,
111 const PositionChangedResult& aResult);
113 virtual PositionChangedResult SetPosition(nsIFrame* aFrame, int32_t aOffset);
115 // Does two AccessibleCarets overlap?
116 bool Intersects(const AccessibleCaret& aCaret) const;
118 // Is the point within the caret's rect? The point should be relative to root
119 // frame.
120 enum class TouchArea {
121 Full, // Contains both text overlay and caret image.
122 CaretImage
124 bool Contains(const nsPoint& aPoint, TouchArea aTouchArea) const;
126 // The geometry center of the imaginary caret (nsCaret) to which this
127 // AccessibleCaret is attached. It is needed when dragging the caret.
128 nsPoint LogicalPosition() const { return mImaginaryCaretRect.Center(); }
130 // Element for 'Intersects' test. This is the container of the caret image
131 // and text-overlay elements. See CreateCaretElement() for the content
132 // structure.
133 dom::Element& CaretElement() const {
134 return mCaretElementHolder->ContentNode();
137 // Ensures that the caret element is made "APZ aware" so that the APZ code
138 // doesn't scroll the page when the user is trying to drag the caret.
139 void EnsureApzAware();
141 bool IsInPositionFixedSubtree() const;
143 protected:
144 // Argument aRect should be relative to CustomContentContainerFrame().
145 void SetCaretElementStyle(const nsRect& aRect, float aZoomLevel);
146 void SetTextOverlayElementStyle(const nsRect& aRect, float aZoomLevel);
147 void SetCaretImageElementStyle(const nsRect& aRect, float aZoomLevel);
149 // Get current zoom level.
150 float GetZoomLevel();
152 // Element which contains the text overly for the 'Contains' test.
153 dom::Element* TextOverlayElement() const {
154 return mCaretElementHolder->GetElementById(sTextOverlayElementId);
157 // Element which contains the caret image for 'Contains' test.
158 dom::Element* CaretImageElement() const {
159 return mCaretElementHolder->GetElementById(sCaretImageElementId);
162 nsIFrame* RootFrame() const;
164 nsIFrame* CustomContentContainerFrame() const;
166 // Transform Appearance to CSS id used in ua.css.
167 static nsAutoString AppearanceString(Appearance aAppearance);
169 already_AddRefed<dom::Element> CreateCaretElement(dom::Document*) const;
171 // Inject caret element into custom content container.
172 void InjectCaretElement(dom::Document*);
174 // Remove caret element from custom content container.
175 void RemoveCaretElement(dom::Document*);
177 // Clear the cached rects and zoom level.
178 void ClearCachedData();
180 // The top-center of the imaginary caret to which this AccessibleCaret is
181 // attached.
182 static nsPoint CaretElementPosition(const nsRect& aRect) {
183 return aRect.TopLeft() + nsPoint(aRect.width / 2, 0);
186 class DummyTouchListener final : public nsIDOMEventListener {
187 public:
188 NS_DECL_ISUPPORTS
189 NS_IMETHOD HandleEvent(mozilla::dom::Event* aEvent) override {
190 return NS_OK;
193 private:
194 virtual ~DummyTouchListener() = default;
197 // Member variables
198 Appearance mAppearance = Appearance::None;
200 // AccessibleCaretManager owns us by a UniquePtr. When it's terminated by
201 // AccessibleCaretEventHub::Terminate() which is called in
202 // PresShell::Destroy(), it frees us automatically. No need to worry if we
203 // outlive mPresShell.
204 PresShell* const MOZ_NON_OWNING_REF mPresShell = nullptr;
206 RefPtr<dom::AnonymousContent> mCaretElementHolder;
208 // This cached rect is relative to the root frame, and is used in
209 // LogicalPosition() when dragging a caret.
210 nsRect mImaginaryCaretRect;
212 // This cached rect is relative to the custom content container, and is used
213 // in SetPosition() to check whether the caret position has changed.
214 nsRect mImaginaryCaretRectInContainerFrame;
216 // The reference frame we used to calculate mImaginaryCaretRect and
217 // mImaginaryCaretRectInContainerFrame.
218 WeakFrame mImaginaryCaretReferenceFrame;
220 // Cache current zoom level to determine whether position is changed.
221 float mZoomLevel = 0.0f;
223 // A no-op touch-start listener which prevents APZ from panning when dragging
224 // the caret.
225 RefPtr<DummyTouchListener> mDummyTouchListener{new DummyTouchListener()};
227 // Static class variables
228 static const nsLiteralString sTextOverlayElementId;
229 static const nsLiteralString sCaretImageElementId;
231 }; // class AccessibleCaret
233 std::ostream& operator<<(std::ostream& aStream,
234 const AccessibleCaret::Appearance& aAppearance);
236 std::ostream& operator<<(std::ostream& aStream,
237 const AccessibleCaret::PositionChangedResult& aResult);
239 } // namespace mozilla
241 #endif // AccessibleCaret_h__