Bug 1055557 - Add a ZoomConstraintsClient class to manage pushing zoom constraints updates to the APZ code. r=botond

Original patch by Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>.
This commit is contained in:
Kartikaya Gupta 2015-06-17 12:32:42 -04:00
Родитель 77b7c32e92
Коммит 49c13c1c35
14 изменённых файлов: 309 добавлений и 44 удалений

Просмотреть файл

@ -311,18 +311,8 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, GetInnerSize());
uint32_t presShellId = 0;
mozilla::layers::FrameMetrics::ViewID viewId = FrameMetrics::NULL_SCROLL_ID;
bool scrollIdentifiersValid = APZCCallbackHelper::GetOrCreateScrollIdentifiers(
APZCCallbackHelper::GetOrCreateScrollIdentifiers(
document->GetDocumentElement(), &presShellId, &viewId);
if (scrollIdentifiersValid) {
ZoomConstraints constraints(
viewportInfo.IsZoomAllowed(),
viewportInfo.IsDoubleTapZoomAllowed(),
ConvertScaleForRoot(viewportInfo.GetMinZoom()),
ConvertScaleForRoot(viewportInfo.GetMaxZoom()));
DoUpdateZoomConstraints(presShellId,
viewId,
Some(constraints));
}
float screenW = GetInnerSize().width;
float screenH = GetInnerSize().height;
@ -469,24 +459,6 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
// displayport, so we start with async painting.
mLastRootMetrics = ProcessUpdateFrame(metrics);
if (viewportInfo.IsZoomAllowed() && scrollIdentifiersValid) {
// If the CSS viewport is narrower than the screen (i.e. width <= device-width)
// then we disable double-tap-to-zoom behaviour.
bool allowDoubleTapZoom = (viewport.width > screenW / metrics.GetDevPixelsPerCSSPixel().scale);
if (allowDoubleTapZoom != viewportInfo.IsDoubleTapZoomAllowed()) {
viewportInfo.SetAllowDoubleTapZoom(allowDoubleTapZoom);
ZoomConstraints constraints(
viewportInfo.IsZoomAllowed(),
viewportInfo.IsDoubleTapZoomAllowed(),
ConvertScaleForRoot(viewportInfo.GetMinZoom()),
ConvertScaleForRoot(viewportInfo.GetMaxZoom()));
DoUpdateZoomConstraints(presShellId,
viewId,
Some(constraints));
}
}
return true;
}
@ -1077,15 +1049,12 @@ TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId,
const ViewID& aViewId,
const Maybe<ZoomConstraints>& aConstraints)
{
ScrollableLayerGuid newGuid(0, aPresShellId, aViewId);
if (mLastZoomConstraintsGuid && newGuid != mLastZoomConstraintsGuid.value()) {
// The guid has changed, so clear the constraints we sent for the previous
// guid.
SendUpdateZoomConstraints(mLastZoomConstraintsGuid->mPresShellId,
mLastZoomConstraintsGuid->mScrollId,
mozilla::void_t());
if (sPreallocatedTab == this) {
// If we're the preallocated tab, bail out because doing IPC will crash.
// Once we get used for something we'll get another zoom constraints update
// and all will be well.
return true;
}
mLastZoomConstraintsGuid = Some(newGuid);
return SendUpdateZoomConstraints(aPresShellId,
aViewId,
@ -2812,11 +2781,6 @@ TabChild::RecvDestroy()
mTabChildGlobal->DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
}
if (mLastZoomConstraintsGuid) {
DoUpdateZoomConstraints(mLastZoomConstraintsGuid->mPresShellId,
mLastZoomConstraintsGuid->mScrollId,
Nothing());
}
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();

Просмотреть файл

@ -658,7 +658,6 @@ private:
bool mParentIsActive;
bool mAsyncPanZoomEnabled;
CSSSize mUnscaledInnerSize;
Maybe<ScrollableLayerGuid> mLastZoomConstraintsGuid;
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
};

Просмотреть файл

@ -1037,7 +1037,7 @@ APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
if (aConstraints) {
APZCTM_LOG("Recording constraints %s for guid %s\n",
Stringify(aConstraints.value()).c_str(), Stringify(aGuid).c_str());
mZoomConstraints[aGuid] = aConstraints.value();
mZoomConstraints[aGuid] = aConstraints.ref();
} else {
APZCTM_LOG("Removing constraints for guid %s\n", Stringify(aGuid).c_str());
mZoomConstraints.erase(aGuid);

Просмотреть файл

@ -22,6 +22,8 @@ namespace mozilla {
enum class PixelCastJustification : uint8_t {
// For the root layer, Screen Pixel = Parent Layer Pixel.
ScreenIsParentLayerForRoot,
// On the layout side, Screen Pixel = LayoutDevice at the outer-window level.
LayoutDeviceIsScreenForBounds,
// For the root layer, Render Target Pixel = Parent Layer Pixel.
RenderTargetIsParentLayerForRoot,
// For the root composition size we want to view it as layer pixels in any layer

Просмотреть файл

@ -0,0 +1,201 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "ZoomConstraintsClient.h"
#include <inttypes.h>
#include "FrameMetrics.h"
#include "LayersLogging.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "nsDocument.h"
#include "nsIFrame.h"
#include "nsLayoutUtils.h"
#include "nsPoint.h"
#include "nsPresShell.h"
#include "nsView.h"
#include "nsViewportInfo.h"
#include "Units.h"
#include "UnitTransforms.h"
#define ZCC_LOG(...)
// #define ZCC_LOG(...) printf_stderr("ZCC: " __VA_ARGS__)
NS_IMPL_ISUPPORTS(ZoomConstraintsClient, nsIDOMEventListener, nsIObserver)
static const nsLiteralString DOM_META_ADDED = NS_LITERAL_STRING("DOMMetaAdded");
static const nsLiteralCString BEFORE_FIRST_PAINT = NS_LITERAL_CSTRING("before-first-paint");
using namespace mozilla;
using namespace mozilla::layers;
ZoomConstraintsClient::ZoomConstraintsClient() :
mDocument(nullptr),
mPresShell(nullptr)
{
}
ZoomConstraintsClient::~ZoomConstraintsClient()
{
}
static nsIWidget*
GetWidget(nsIPresShell* aShell)
{
if (nsIFrame* rootFrame = aShell->GetRootFrame()) {
#ifdef MOZ_WIDGET_ANDROID
return rootFrame->GetNearestWidget();
#else
if (nsView* view = rootFrame->GetView()) {
return view->GetWidget();
}
#endif
}
return nullptr;
}
void
ZoomConstraintsClient::Destroy()
{
if (!(mPresShell && mDocument)) {
return;
}
ZCC_LOG("Destroying %p\n", this);
if (mEventTarget) {
mEventTarget->RemoveEventListener(DOM_META_ADDED, this, false);
mEventTarget = nullptr;
}
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (observerService) {
observerService->RemoveObserver(this, BEFORE_FIRST_PAINT.Data());
}
if (mGuid) {
if (nsIWidget* widget = GetWidget(mPresShell)) {
ZCC_LOG("Sending null constraints in %p for { %u, %" PRIu64 " }\n",
this, mGuid->mPresShellId, mGuid->mScrollId);
widget->UpdateZoomConstraints(mGuid->mPresShellId, mGuid->mScrollId, Nothing());
mGuid = Nothing();
}
}
mDocument = nullptr;
mPresShell = nullptr;
}
void
ZoomConstraintsClient::Init(nsIPresShell* aPresShell, nsIDocument* aDocument)
{
if (!(aPresShell && aDocument)) {
return;
}
mPresShell = aPresShell;
mDocument = aDocument;
if (nsCOMPtr<nsPIDOMWindow> window = mDocument->GetWindow()) {
mEventTarget = window->GetChromeEventHandler();
}
if (mEventTarget) {
mEventTarget->AddEventListener(DOM_META_ADDED, this, false);
}
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, BEFORE_FIRST_PAINT.Data(), false);
}
}
NS_IMETHODIMP
ZoomConstraintsClient::HandleEvent(nsIDOMEvent* event)
{
nsAutoString type;
event->GetType(type);
if (type.Equals(DOM_META_ADDED)) {
ZCC_LOG("Got a dom-meta-added event in %p\n", this);
RefreshZoomConstraints();
}
return NS_OK;
}
NS_IMETHODIMP
ZoomConstraintsClient::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
{
if (SameCOMIdentity(aSubject, mDocument) && BEFORE_FIRST_PAINT.EqualsASCII(aTopic)) {
ZCC_LOG("Got a before-first-paint event in %p\n", this);
RefreshZoomConstraints();
}
return NS_OK;
}
mozilla::layers::ZoomConstraints
ComputeZoomConstraintsFromViewportInfo(const nsViewportInfo& aViewportInfo)
{
mozilla::layers::ZoomConstraints constraints;
constraints.mAllowZoom = aViewportInfo.IsZoomAllowed();
constraints.mAllowDoubleTapZoom = aViewportInfo.IsDoubleTapZoomAllowed();
constraints.mMinZoom.scale = aViewportInfo.GetMinZoom().scale;
constraints.mMaxZoom.scale = aViewportInfo.GetMaxZoom().scale;
return constraints;
}
void
ZoomConstraintsClient::RefreshZoomConstraints()
{
nsIWidget* widget = GetWidget(mPresShell);
if (!widget) {
return;
}
uint32_t presShellId = 0;
FrameMetrics::ViewID viewId = FrameMetrics::NULL_SCROLL_ID;
bool scrollIdentifiersValid = APZCCallbackHelper::GetOrCreateScrollIdentifiers(
mDocument->GetDocumentElement(),
&presShellId, &viewId);
if (!scrollIdentifiersValid) {
return;
}
nsIFrame* rootFrame = mPresShell->GetRootScrollFrame();
if (!rootFrame) {
rootFrame = mPresShell->GetRootFrame();
}
nsSize size = nsLayoutUtils::CalculateCompositionSizeForFrame(rootFrame, false);
int32_t auPerDevPixel = mPresShell->GetPresContext()->AppUnitsPerDevPixel();
LayoutDeviceIntSize screenSize = LayoutDeviceIntSize::FromAppUnitsRounded(
size, auPerDevPixel);
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(
mDocument,
ViewAs<ScreenPixel>(screenSize, PixelCastJustification::LayoutDeviceIsScreenForBounds));
mozilla::layers::ZoomConstraints zoomConstraints =
ComputeZoomConstraintsFromViewportInfo(viewportInfo);
if (zoomConstraints.mAllowDoubleTapZoom) {
// If the CSS viewport is narrower than the screen (i.e. width <= device-width)
// then we disable double-tap-to-zoom behaviour.
CSSToLayoutDeviceScale scale(
(float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel);
if ((viewportInfo.GetSize() * scale).width <= screenSize.width) {
zoomConstraints.mAllowDoubleTapZoom = false;
}
}
ScrollableLayerGuid newGuid(0, presShellId, viewId);
if (mGuid && mGuid.value() != newGuid) {
ZCC_LOG("Clearing old constraints in %p for { %u, %" PRIu64 " }\n",
this, mGuid->mPresShellId, mGuid->mScrollId);
// If the guid changes, send a message to clear the old one
widget->UpdateZoomConstraints(mGuid->mPresShellId, mGuid->mScrollId, Nothing());
}
mGuid = Some(newGuid);
ZCC_LOG("Sending constraints %s in %p for { %u, %" PRIu64 " }\n",
Stringify(zoomConstraints).c_str(), this, presShellId, viewId);
widget->UpdateZoomConstraints(presShellId, viewId, Some(zoomConstraints));
}

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef ZoomConstraintsClient_h_
#define ZoomConstraintsClient_h_
#include "FrameMetrics.h"
#include "mozilla/Maybe.h"
#include "nsIDOMEventListener.h"
#include "nsIDocument.h"
#include "nsIObserver.h"
#include "nsWeakPtr.h"
class nsIDOMEventTarget;
class nsIDocument;
class nsIPresShell;
class ZoomConstraintsClient final : public nsIDOMEventListener,
public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIOBSERVER
ZoomConstraintsClient();
private:
~ZoomConstraintsClient();
public:
void Init(nsIPresShell* aPresShell, nsIDocument *aDocument);
void Destroy();
private:
void RefreshZoomConstraints();
nsCOMPtr<nsIDocument> mDocument;
nsIPresShell* MOZ_NON_OWNING_REF mPresShell; // raw ref since the presShell owns this
nsCOMPtr<nsIDOMEventTarget> mEventTarget;
mozilla::Maybe<mozilla::layers::ScrollableLayerGuid> mGuid;
};
#endif

Просмотреть файл

@ -143,6 +143,7 @@ UNIFIED_SOURCES += [
'StackArena.cpp',
'TouchCaret.cpp',
'TouchManager.cpp',
'ZoomConstraintsClient.cpp',
]
# nsPresArena.cpp needs to be built separately because it uses plarena.h.

Просмотреть файл

@ -979,6 +979,11 @@ PresShell::Init(nsIDocument* aDocument,
SetupFontInflation();
mTouchManager.Init(this, mDocument);
if (mPresContext->IsRootContentDocument()) {
mZoomConstraintsClient = new ZoomConstraintsClient();
mZoomConstraintsClient->Init(this, mDocument);
}
}
enum TextPerfLogType {
@ -1092,6 +1097,11 @@ PresShell::Destroy()
if (mHaveShutDown)
return;
if (mZoomConstraintsClient) {
mZoomConstraintsClient->Destroy();
mZoomConstraintsClient = nullptr;
}
#ifdef ACCESSIBILITY
if (mDocAccessible) {
#ifdef DEBUG

Просмотреть файл

@ -36,6 +36,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/MemoryReporting.h"
#include "ZoomConstraintsClient.h"
class nsRange;
@ -809,6 +810,8 @@ protected:
// TouchManager
TouchManager mTouchManager;
nsRefPtr<ZoomConstraintsClient> mZoomConstraintsClient;
// TouchCaret
nsRefPtr<mozilla::TouchCaret> mTouchCaret;
nsRefPtr<mozilla::SelectionCarets> mSelectionCarets;

Просмотреть файл

@ -485,6 +485,16 @@ PuppetWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
}
}
void
PuppetWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const Maybe<ZoomConstraints>& aConstraints)
{
if (mTabChild) {
mTabChild->DoUpdateZoomConstraints(aPresShellId, aViewId, aConstraints);
}
}
bool
PuppetWidget::AsyncPanZoomEnabled() const
{

Просмотреть файл

@ -136,6 +136,9 @@ public:
nsEventStatus DispatchInputEvent(WidgetInputEvent* aEvent) override;
void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const override;
void UpdateZoomConstraints(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const mozilla::Maybe<ZoomConstraints>& aConstraints) override;
bool AsyncPanZoomEnabled() const override;
NS_IMETHOD CaptureRollupEvents(nsIRollupListener* aListener,

Просмотреть файл

@ -1011,6 +1011,19 @@ nsBaseWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
mAPZC.get(), setTargetApzcFunc, aInputBlockId, mozilla::Move(aTargets)));
}
void
nsBaseWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const Maybe<ZoomConstraints>& aConstraints)
{
if (!mCompositorParent || !mAPZC) {
return;
}
uint64_t layersId = mCompositorParent->RootLayerTreeId();
mAPZC->UpdateZoomConstraints(ScrollableLayerGuid(layersId, aPresShellId, aViewId),
aConstraints);
}
bool
nsBaseWidget::AsyncPanZoomEnabled() const
{

Просмотреть файл

@ -243,6 +243,10 @@ public:
void SetConfirmedTargetAPZC(uint64_t aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets) const override;
void UpdateZoomConstraints(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const mozilla::Maybe<ZoomConstraints>& aConstraints) override;
bool AsyncPanZoomEnabled() const override;
void NotifyWindowDestroyed();

Просмотреть файл

@ -18,6 +18,7 @@
#include "nsITheme.h"
#include "nsITimer.h"
#include "nsXULAppAPI.h"
#include "mozilla/Maybe.h"
#include "mozilla/EventForwards.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/RefPtr.h"
@ -25,6 +26,7 @@
#include "mozilla/gfx/Point.h"
#include "nsDataHashtable.h"
#include "nsIObserver.h"
#include "FrameMetrics.h"
#include "Units.h"
// forward declarations
@ -818,10 +820,12 @@ class nsIWidget : public nsISupports {
public:
typedef mozilla::layers::Composer2D Composer2D;
typedef mozilla::layers::CompositorChild CompositorChild;
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::LayerManagerComposite LayerManagerComposite;
typedef mozilla::layers::LayersBackend LayersBackend;
typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
typedef mozilla::layers::ZoomConstraints ZoomConstraints;
typedef mozilla::widget::IMEMessage IMEMessage;
typedef mozilla::widget::IMENotification IMENotification;
typedef mozilla::widget::IMEState IMEState;
@ -2438,6 +2442,10 @@ public:
*/
virtual int32_t RoundsWidgetCoordinatesTo() { return 1; }
virtual void UpdateZoomConstraints(const uint32_t& aPresShellId,
const FrameMetrics::ViewID& aViewId,
const mozilla::Maybe<ZoomConstraints>& aConstraints) {};
/**
* GetTextEventDispatcher() returns TextEventDispatcher belonging to the
* widget. Note that this never returns nullptr.