2018-08-20 23:28:42 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#include "VisualViewport.h"
|
2018-12-21 00:35:26 +03:00
|
|
|
|
|
|
|
#include "mozilla/EventDispatcher.h"
|
2018-08-20 23:28:42 +03:00
|
|
|
#include "nsIScrollableFrame.h"
|
|
|
|
#include "nsIDocShell.h"
|
2018-12-21 00:35:26 +03:00
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsRefreshDriver.h"
|
|
|
|
|
|
|
|
#define VVP_LOG(...)
|
|
|
|
// #define VVP_LOG(...) printf_stderr("VVP: " __VA_ARGS__)
|
2018-08-20 23:28:42 +03:00
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
|
|
|
VisualViewport::VisualViewport(nsPIDOMWindowInner* aWindow)
|
|
|
|
: DOMEventTargetHelper(aWindow) {}
|
|
|
|
|
2018-12-21 00:35:26 +03:00
|
|
|
VisualViewport::~VisualViewport() {
|
|
|
|
if (mResizeEvent) {
|
|
|
|
mResizeEvent->Revoke();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mScrollEvent) {
|
|
|
|
mScrollEvent->Revoke();
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 23:28:42 +03:00
|
|
|
|
|
|
|
/* virtual */
|
|
|
|
JSObject* VisualViewport::WrapObject(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGivenProto) {
|
|
|
|
return VisualViewport_Binding::Wrap(aCx, this, aGivenProto);
|
|
|
|
}
|
|
|
|
|
|
|
|
CSSSize VisualViewport::VisualViewportSize() const {
|
|
|
|
CSSSize size = CSSSize(0, 0);
|
|
|
|
|
|
|
|
nsIPresShell* presShell = GetPresShell();
|
|
|
|
if (presShell) {
|
|
|
|
if (presShell->IsVisualViewportSizeSet()) {
|
|
|
|
size = CSSRect::FromAppUnits(presShell->GetVisualViewportSize());
|
|
|
|
} else {
|
|
|
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
|
|
|
if (sf) {
|
|
|
|
size = CSSRect::FromAppUnits(sf->GetScrollPortRect().Size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
double VisualViewport::Width() const {
|
|
|
|
CSSSize size = VisualViewportSize();
|
|
|
|
return size.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
double VisualViewport::Height() const {
|
|
|
|
CSSSize size = VisualViewportSize();
|
|
|
|
return size.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
double VisualViewport::Scale() const {
|
|
|
|
double scale = 1;
|
|
|
|
nsIPresShell* presShell = GetPresShell();
|
|
|
|
if (presShell) {
|
|
|
|
scale = presShell->GetResolution();
|
|
|
|
}
|
|
|
|
return scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSSPoint VisualViewport::VisualViewportOffset() const {
|
|
|
|
CSSPoint offset = CSSPoint(0, 0);
|
|
|
|
|
|
|
|
nsIPresShell* presShell = GetPresShell();
|
|
|
|
if (presShell) {
|
|
|
|
offset = CSSPoint::FromAppUnits(presShell->GetVisualViewportOffset());
|
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSSPoint VisualViewport::LayoutViewportOffset() const {
|
|
|
|
CSSPoint offset = CSSPoint(0, 0);
|
|
|
|
|
|
|
|
nsIPresShell* presShell = GetPresShell();
|
|
|
|
if (presShell) {
|
|
|
|
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
|
|
|
if (sf) {
|
|
|
|
offset = CSSPoint::FromAppUnits(sf->GetScrollPosition());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
double VisualViewport::PageLeft() const { return VisualViewportOffset().X(); }
|
|
|
|
|
|
|
|
double VisualViewport::PageTop() const { return VisualViewportOffset().Y(); }
|
|
|
|
|
|
|
|
double VisualViewport::OffsetLeft() const {
|
|
|
|
return PageLeft() - LayoutViewportOffset().X();
|
|
|
|
}
|
|
|
|
|
|
|
|
double VisualViewport::OffsetTop() const {
|
|
|
|
return PageTop() - LayoutViewportOffset().Y();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIPresShell* VisualViewport::GetPresShell() const {
|
|
|
|
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
|
|
|
|
if (!window) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocShell* docShell = window->GetDocShell();
|
|
|
|
if (!docShell) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return docShell->GetPresShell();
|
|
|
|
}
|
2018-12-21 00:35:26 +03:00
|
|
|
|
|
|
|
nsPresContext* VisualViewport::GetPresContext() const {
|
|
|
|
nsIPresShell* presShell = GetPresShell();
|
|
|
|
if (!presShell) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return presShell->GetPresContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ================= Resize event handling ================= */
|
|
|
|
|
|
|
|
void VisualViewport::PostResizeEvent() {
|
|
|
|
VVP_LOG("%p: PostResizeEvent\n", this);
|
|
|
|
if (mResizeEvent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The event constructor will register itself with the refresh driver.
|
|
|
|
if (nsPresContext* presContext = GetPresContext()) {
|
|
|
|
mResizeEvent = new VisualViewportResizeEvent(this, presContext);
|
|
|
|
VVP_LOG("%p: PostResizeEvent, created new event\n", this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VisualViewport::VisualViewportResizeEvent::VisualViewportResizeEvent(
|
|
|
|
VisualViewport* aViewport, nsPresContext* aPresContext)
|
|
|
|
: Runnable("VisualViewport::VisualViewportResizeEvent"),
|
|
|
|
mViewport(aViewport) {
|
|
|
|
aPresContext->RefreshDriver()->PostVisualViewportResizeEvent(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VisualViewport::VisualViewportResizeEvent::Run() {
|
|
|
|
if (mViewport) {
|
|
|
|
mViewport->FireResizeEvent();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisualViewport::FireResizeEvent() {
|
|
|
|
MOZ_ASSERT(mResizeEvent);
|
|
|
|
mResizeEvent->Revoke();
|
|
|
|
mResizeEvent = nullptr;
|
|
|
|
|
|
|
|
VVP_LOG("%p, FireResizeEvent, fire VisualViewport resize\n", this);
|
|
|
|
WidgetEvent event(true, eResize);
|
|
|
|
event.mFlags.mBubbles = false;
|
|
|
|
event.mFlags.mCancelable = false;
|
|
|
|
EventDispatcher::Dispatch(this, GetPresContext(), &event);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ================= Scroll event handling ================= */
|
|
|
|
|
|
|
|
void VisualViewport::PostScrollEvent() {
|
|
|
|
VVP_LOG("%p: PostScrollEvent\n", this);
|
|
|
|
if (mScrollEvent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The event constructor will register itself with the refresh driver.
|
|
|
|
if (nsPresContext* presContext = GetPresContext()) {
|
|
|
|
mScrollEvent = new VisualViewportScrollEvent(this, presContext);
|
|
|
|
VVP_LOG("%p: PostScrollEvent, created new event\n", this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VisualViewport::VisualViewportScrollEvent::VisualViewportScrollEvent(
|
|
|
|
VisualViewport* aViewport, nsPresContext* aPresContext)
|
|
|
|
: Runnable("VisualViewport::VisualViewportScrollEvent"),
|
|
|
|
mViewport(aViewport) {
|
|
|
|
aPresContext->RefreshDriver()->PostVisualViewportScrollEvent(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
VisualViewport::VisualViewportScrollEvent::Run() {
|
|
|
|
if (mViewport) {
|
|
|
|
mViewport->FireScrollEvent();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VisualViewport::FireScrollEvent() {
|
|
|
|
MOZ_ASSERT(mScrollEvent);
|
|
|
|
mScrollEvent->Revoke();
|
|
|
|
mScrollEvent = nullptr;
|
|
|
|
|
|
|
|
VVP_LOG("%p, FireScrollEvent, fire VisualViewport scroll\n", this);
|
|
|
|
WidgetGUIEvent event(true, eScroll, nullptr);
|
|
|
|
event.mFlags.mBubbles = false;
|
|
|
|
event.mFlags.mCancelable = false;
|
|
|
|
EventDispatcher::Dispatch(this, GetPresContext(), &event);
|
|
|
|
}
|