Coverage Report

Created: 2018-09-25 14:53

/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__