Bug 1700051: part 35) Reduce accessibility of `mSoftText.mDOMMapping` to `private...
[gecko.git] / dom / base / VisualViewport.cpp
blobe89c0f04921dc6e7d257d9d90c402d10cf1ba864
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 #include "VisualViewport.h"
9 #include "mozilla/EventDispatcher.h"
10 #include "mozilla/PresShell.h"
11 #include "mozilla/ToString.h"
12 #include "nsIScrollableFrame.h"
13 #include "nsIDocShell.h"
14 #include "nsPresContext.h"
15 #include "nsRefreshDriver.h"
16 #include "DocumentInlines.h"
18 static mozilla::LazyLogModule sVvpLog("visualviewport");
19 #define VVP_LOG(...) MOZ_LOG(sVvpLog, LogLevel::Debug, (__VA_ARGS__))
21 using namespace mozilla;
22 using namespace mozilla::dom;
24 VisualViewport::VisualViewport(nsPIDOMWindowInner* aWindow)
25 : DOMEventTargetHelper(aWindow) {}
27 VisualViewport::~VisualViewport() {
28 if (mResizeEvent) {
29 mResizeEvent->Revoke();
32 if (mScrollEvent) {
33 mScrollEvent->Revoke();
37 /* virtual */
38 JSObject* VisualViewport::WrapObject(JSContext* aCx,
39 JS::Handle<JSObject*> aGivenProto) {
40 return VisualViewport_Binding::Wrap(aCx, this, aGivenProto);
43 /* virtual */
44 void VisualViewport::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
45 EventMessage msg = aVisitor.mEvent->mMessage;
47 aVisitor.mCanHandle = true;
48 EventTarget* parentTarget = nullptr;
49 // Only our special internal events are allowed to escape the
50 // Visual Viewport and be dispatched further up the DOM tree.
51 if (msg == eMozVisualScroll || msg == eMozVisualResize) {
52 if (nsPIDOMWindowInner* win = GetOwner()) {
53 if (Document* doc = win->GetExtantDoc()) {
54 parentTarget = doc;
58 aVisitor.SetParentTarget(parentTarget, false);
61 CSSSize VisualViewport::VisualViewportSize() const {
62 CSSSize size = CSSSize(0, 0);
64 // Flush layout, as that may affect the answer below (e.g. scrollbars
65 // may have appeared, decreasing the available viewport size).
66 RefPtr<const VisualViewport> kungFuDeathGrip(this);
67 if (Document* doc = GetDocument()) {
68 doc->FlushPendingNotifications(FlushType::Layout);
71 // Fetch the pres shell after the layout flush, as it might have destroyed it.
72 if (PresShell* presShell = GetPresShell()) {
73 if (presShell->IsVisualViewportSizeSet()) {
74 DynamicToolbarState state = presShell->GetDynamicToolbarState();
75 size = CSSRect::FromAppUnits(
76 (state == DynamicToolbarState::InTransition ||
77 state == DynamicToolbarState::Collapsed)
78 ? presShell->GetVisualViewportSizeUpdatedByDynamicToolbar()
79 : presShell->GetVisualViewportSize());
80 } else {
81 nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
82 if (sf) {
83 size = CSSRect::FromAppUnits(sf->GetScrollPortRect().Size());
87 return size;
90 double VisualViewport::Width() const {
91 CSSSize size = VisualViewportSize();
92 return size.width;
95 double VisualViewport::Height() const {
96 CSSSize size = VisualViewportSize();
97 return size.height;
100 double VisualViewport::Scale() const {
101 double scale = 1;
102 if (PresShell* presShell = GetPresShell()) {
103 scale = presShell->GetResolution();
105 return scale;
108 CSSPoint VisualViewport::VisualViewportOffset() const {
109 CSSPoint offset = CSSPoint(0, 0);
111 if (PresShell* presShell = GetPresShell()) {
112 offset = CSSPoint::FromAppUnits(presShell->GetVisualViewportOffset());
114 return offset;
117 CSSPoint VisualViewport::LayoutViewportOffset() const {
118 CSSPoint offset = CSSPoint(0, 0);
120 if (PresShell* presShell = GetPresShell()) {
121 offset = CSSPoint::FromAppUnits(presShell->GetLayoutViewportOffset());
123 return offset;
126 double VisualViewport::PageLeft() const { return VisualViewportOffset().X(); }
128 double VisualViewport::PageTop() const { return VisualViewportOffset().Y(); }
130 double VisualViewport::OffsetLeft() const {
131 return PageLeft() - LayoutViewportOffset().X();
134 double VisualViewport::OffsetTop() const {
135 return PageTop() - LayoutViewportOffset().Y();
138 Document* VisualViewport::GetDocument() const {
139 nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
140 if (!window) {
141 return nullptr;
144 nsIDocShell* docShell = window->GetDocShell();
145 if (!docShell) {
146 return nullptr;
149 return docShell->GetDocument();
152 PresShell* VisualViewport::GetPresShell() const {
153 RefPtr<Document> document = GetDocument();
154 return document ? document->GetPresShell() : nullptr;
157 nsPresContext* VisualViewport::GetPresContext() const {
158 RefPtr<Document> document = GetDocument();
159 return document ? document->GetPresContext() : nullptr;
162 /* ================= Resize event handling ================= */
164 void VisualViewport::PostResizeEvent() {
165 VVP_LOG("%p: PostResizeEvent (pre-existing: %d)\n", this, !!mResizeEvent);
166 nsPresContext* presContext = GetPresContext();
167 if (mResizeEvent && mResizeEvent->HasPresContext(presContext)) {
168 return;
170 if (mResizeEvent) {
171 // prescontext changed, so discard the old resize event and queue a new one
172 mResizeEvent->Revoke();
173 mResizeEvent = nullptr;
176 // The event constructor will register itself with the refresh driver.
177 if (presContext) {
178 mResizeEvent = new VisualViewportResizeEvent(this, presContext);
179 VVP_LOG("%p: PostResizeEvent, created new event\n", this);
183 VisualViewport::VisualViewportResizeEvent::VisualViewportResizeEvent(
184 VisualViewport* aViewport, nsPresContext* aPresContext)
185 : Runnable("VisualViewport::VisualViewportResizeEvent"),
186 mViewport(aViewport),
187 mPresContext(aPresContext) {
188 VVP_LOG("%p: Registering PostResize on %p %p\n", aViewport, aPresContext,
189 aPresContext->RefreshDriver());
190 aPresContext->RefreshDriver()->PostVisualViewportResizeEvent(this);
193 bool VisualViewport::VisualViewportResizeEvent::HasPresContext(
194 nsPresContext* aContext) const {
195 return mPresContext.get() == aContext;
198 void VisualViewport::VisualViewportResizeEvent::Revoke() {
199 mViewport = nullptr;
200 mPresContext = nullptr;
203 NS_IMETHODIMP
204 VisualViewport::VisualViewportResizeEvent::Run() {
205 if (mViewport) {
206 mViewport->FireResizeEvent();
208 return NS_OK;
211 void VisualViewport::FireResizeEvent() {
212 MOZ_ASSERT(mResizeEvent);
213 mResizeEvent->Revoke();
214 mResizeEvent = nullptr;
216 VVP_LOG("%p, FireResizeEvent, fire mozvisualresize\n", this);
217 WidgetEvent mozEvent(true, eMozVisualResize);
218 mozEvent.mFlags.mOnlySystemGroupDispatch = true;
219 EventDispatcher::Dispatch(this, GetPresContext(), &mozEvent);
221 VVP_LOG("%p, FireResizeEvent, fire VisualViewport resize\n", this);
222 WidgetEvent event(true, eResize);
223 event.mFlags.mBubbles = false;
224 event.mFlags.mCancelable = false;
225 EventDispatcher::Dispatch(this, GetPresContext(), &event);
228 /* ================= Scroll event handling ================= */
230 void VisualViewport::PostScrollEvent(const nsPoint& aPrevVisualOffset,
231 const nsPoint& aPrevLayoutOffset) {
232 VVP_LOG("%p: PostScrollEvent, prevRelativeOffset=%s (pre-existing: %d)\n",
233 this, ToString(aPrevVisualOffset - aPrevLayoutOffset).c_str(),
234 !!mScrollEvent);
235 nsPresContext* presContext = GetPresContext();
236 if (mScrollEvent && mScrollEvent->HasPresContext(presContext)) {
237 return;
240 if (mScrollEvent) {
241 // prescontext changed, so discard the old scroll event and queue a new one
242 mScrollEvent->Revoke();
243 mScrollEvent = nullptr;
246 // The event constructor will register itself with the refresh driver.
247 if (presContext) {
248 mScrollEvent = new VisualViewportScrollEvent(
249 this, presContext, aPrevVisualOffset, aPrevLayoutOffset);
250 VVP_LOG("%p: PostScrollEvent, created new event\n", this);
254 VisualViewport::VisualViewportScrollEvent::VisualViewportScrollEvent(
255 VisualViewport* aViewport, nsPresContext* aPresContext,
256 const nsPoint& aPrevVisualOffset, const nsPoint& aPrevLayoutOffset)
257 : Runnable("VisualViewport::VisualViewportScrollEvent"),
258 mViewport(aViewport),
259 mPresContext(aPresContext),
260 mPrevVisualOffset(aPrevVisualOffset),
261 mPrevLayoutOffset(aPrevLayoutOffset) {
262 VVP_LOG("%p: Registering PostScroll on %p %p\n", aViewport, aPresContext,
263 aPresContext->RefreshDriver());
264 aPresContext->RefreshDriver()->PostVisualViewportScrollEvent(this);
267 bool VisualViewport::VisualViewportScrollEvent::HasPresContext(
268 nsPresContext* aContext) const {
269 return mPresContext.get() == aContext;
272 void VisualViewport::VisualViewportScrollEvent::Revoke() {
273 mViewport = nullptr;
274 mPresContext = nullptr;
277 NS_IMETHODIMP
278 VisualViewport::VisualViewportScrollEvent::Run() {
279 if (mViewport) {
280 mViewport->FireScrollEvent();
282 return NS_OK;
285 void VisualViewport::FireScrollEvent() {
286 MOZ_ASSERT(mScrollEvent);
287 nsPoint prevVisualOffset = mScrollEvent->PrevVisualOffset();
288 nsPoint prevLayoutOffset = mScrollEvent->PrevLayoutOffset();
289 mScrollEvent->Revoke();
290 mScrollEvent = nullptr;
292 if (PresShell* presShell = GetPresShell()) {
293 if (presShell->GetVisualViewportOffset() != prevVisualOffset) {
294 // The internal event will be fired whenever the visual viewport's
295 // *absolute* offset changed, i.e. relative to the page.
296 VVP_LOG("%p: FireScrollEvent, fire mozvisualscroll\n", this);
297 WidgetEvent mozEvent(true, eMozVisualScroll);
298 mozEvent.mFlags.mOnlySystemGroupDispatch = true;
299 EventDispatcher::Dispatch(this, GetPresContext(), &mozEvent);
302 // Check whether the relative visual viewport offset actually changed -
303 // maybe both visual and layout viewport scrolled together and there was no
304 // change after all.
305 nsPoint curRelativeOffset =
306 presShell->GetVisualViewportOffsetRelativeToLayoutViewport();
307 nsPoint prevRelativeOffset = prevVisualOffset - prevLayoutOffset;
308 VVP_LOG(
309 "%p: FireScrollEvent, curRelativeOffset %s, "
310 "prevRelativeOffset %s\n",
311 this, ToString(curRelativeOffset).c_str(),
312 ToString(prevRelativeOffset).c_str());
313 if (curRelativeOffset != prevRelativeOffset) {
314 VVP_LOG("%p, FireScrollEvent, fire VisualViewport scroll\n", this);
315 WidgetGUIEvent event(true, eScroll, nullptr);
316 event.mFlags.mBubbles = false;
317 event.mFlags.mCancelable = false;
318 EventDispatcher::Dispatch(this, GetPresContext(), &event);