mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 775463: Implement double-tap-to-zoom content r=cjones
This commit is contained in:
parent
c3543b66ba
commit
de15346fad
@ -9,6 +9,7 @@ const ContentPanning = {
|
||||
});
|
||||
|
||||
addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
|
||||
addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
|
||||
},
|
||||
|
||||
handleEvent: function cp_handleEvent(evt) {
|
||||
@ -200,21 +201,34 @@ const ContentPanning = {
|
||||
},
|
||||
|
||||
_recvViewportChange: function(data) {
|
||||
let viewport = data.json;
|
||||
let displayPort = viewport.displayPort;
|
||||
let metrics = data.json;
|
||||
let displayPort = metrics.displayPort;
|
||||
|
||||
let screenWidth = viewport.screenSize.width;
|
||||
let screenHeight = viewport.screenSize.height;
|
||||
let screenWidth = metrics.screenSize.width;
|
||||
let screenHeight = metrics.screenSize.height;
|
||||
|
||||
let x = viewport.x;
|
||||
let y = viewport.y;
|
||||
let x = metrics.x;
|
||||
let y = metrics.y;
|
||||
|
||||
this._zoom = metrics.zoom;
|
||||
this._viewport = new Rect(x, y,
|
||||
screenWidth / metrics.zoom,
|
||||
screenHeight / metrics.zoom);
|
||||
this._cssPageRect = new Rect(metrics.cssPageRect.x,
|
||||
metrics.cssPageRect.y,
|
||||
metrics.cssPageRect.width,
|
||||
metrics.cssPageRect.height);
|
||||
|
||||
let cwu = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
cwu.setCSSViewport(screenWidth, screenHeight);
|
||||
if (this._screenWidth != screenWidth || this._screenHeight != screenHeight) {
|
||||
cwu.setCSSViewport(screenWidth, screenHeight);
|
||||
this._screenWidth = screenWidth;
|
||||
this._screenHeight = screenHeight;
|
||||
}
|
||||
|
||||
// Set scroll position
|
||||
cwu.setScrollPositionClampingScrollPortSize(
|
||||
screenWidth / viewport.zoom, screenHeight / viewport.zoom);
|
||||
screenWidth / metrics.zoom, screenHeight / metrics.zoom);
|
||||
content.scrollTo(x, y);
|
||||
cwu.setResolution(displayPort.resolution, displayPort.resolution);
|
||||
|
||||
@ -226,6 +240,109 @@ const ContentPanning = {
|
||||
displayPort.height,
|
||||
element);
|
||||
}
|
||||
},
|
||||
|
||||
_recvDoubleTap: function(data) {
|
||||
let data = data.json;
|
||||
|
||||
// We haven't received a metrics update yet; don't do anything.
|
||||
if (this._viewport == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let win = content;
|
||||
|
||||
let zoom = this._zoom;
|
||||
let element = ElementTouchHelper.anyElementFromPoint(win, data.x, data.y);
|
||||
if (!element) {
|
||||
this._zoomOut();
|
||||
return;
|
||||
}
|
||||
|
||||
while (element && !this._shouldZoomToElement(element))
|
||||
element = element.parentNode;
|
||||
|
||||
if (!element) {
|
||||
this._zoomOut();
|
||||
} else {
|
||||
const margin = 15;
|
||||
let rect = ElementTouchHelper.getBoundingContentRect(element);
|
||||
|
||||
let cssPageRect = this._cssPageRect;
|
||||
let viewport = this._viewport;
|
||||
let bRect = new Rect(Math.max(cssPageRect.left, rect.x - margin),
|
||||
rect.y,
|
||||
rect.w + 2 * margin,
|
||||
rect.h);
|
||||
// constrict the rect to the screen's right edge
|
||||
bRect.width = Math.min(bRect.width, cssPageRect.right - bRect.x);
|
||||
|
||||
// if the rect is already taking up most of the visible area and is stretching the
|
||||
// width of the page, then we want to zoom out instead.
|
||||
if (this._isRectZoomedIn(bRect, viewport)) {
|
||||
this._zoomOut();
|
||||
return;
|
||||
}
|
||||
|
||||
rect.x = Math.round(bRect.x);
|
||||
rect.y = Math.round(bRect.y);
|
||||
rect.w = Math.round(bRect.width);
|
||||
rect.h = Math.round(Math.min(bRect.width * viewport.height / viewport.height, bRect.height));
|
||||
|
||||
// if the block we're zooming to is really tall, and the user double-tapped
|
||||
// more than a screenful of height from the top of it, then adjust the y-coordinate
|
||||
// so that we center the actual point the user double-tapped upon. this prevents
|
||||
// flying to the top of a page when double-tapping to zoom in (bug 761721).
|
||||
// the 1.2 multiplier is just a little fuzz to compensate for bRect including horizontal
|
||||
// margins but not vertical ones.
|
||||
let cssTapY = viewport.y + data.y;
|
||||
if ((bRect.height > rect.h) && (cssTapY > rect.y + (rect.h * 1.2))) {
|
||||
rect.y = cssTapY - (rect.h / 2);
|
||||
}
|
||||
|
||||
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
os.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
|
||||
}
|
||||
},
|
||||
|
||||
_shouldZoomToElement: function(aElement) {
|
||||
let win = aElement.ownerDocument.defaultView;
|
||||
if (win.getComputedStyle(aElement, null).display == "inline")
|
||||
return false;
|
||||
if (aElement instanceof Ci.nsIDOMHTMLLIElement)
|
||||
return false;
|
||||
if (aElement instanceof Ci.nsIDOMHTMLQuoteElement)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
_zoomOut: function() {
|
||||
let rect = new Rect(0, 0, 0, 0);
|
||||
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
os.notifyObservers(docShell, 'browser-zoom-to-rect', JSON.stringify(rect));
|
||||
},
|
||||
|
||||
_isRectZoomedIn: function(aRect, aViewport) {
|
||||
// This function checks to see if the area of the rect visible in the
|
||||
// viewport (i.e. the "overlapArea" variable below) is approximately
|
||||
// the max area of the rect we can show. It also checks that the rect
|
||||
// is actually on-screen by testing the left and right edges of the rect.
|
||||
// In effect, this tells us whether or not zooming in to this rect
|
||||
// will significantly change what the user is seeing.
|
||||
const minDifference = -20;
|
||||
const maxDifference = 20;
|
||||
|
||||
let vRect = new Rect(aViewport.x, aViewport.y, aViewport.width, aViewport.height);
|
||||
let overlap = vRect.intersect(aRect);
|
||||
let overlapArea = overlap.width * overlap.height;
|
||||
let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
|
||||
let showing = overlapArea / (aRect.width * availHeight);
|
||||
let dw = (aRect.width - vRect.width);
|
||||
let dx = (aRect.x - vRect.x);
|
||||
|
||||
return (showing > 0.9 &&
|
||||
dx > minDifference && dx < maxDifference &&
|
||||
dw > minDifference && dw < maxDifference);
|
||||
}
|
||||
};
|
||||
|
||||
@ -399,3 +516,52 @@ const KineticPanning = {
|
||||
content.mozRequestAnimationFrame(callback);
|
||||
}
|
||||
};
|
||||
|
||||
const ElementTouchHelper = {
|
||||
anyElementFromPoint: function(aWindow, aX, aY) {
|
||||
let cwu = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
let elem = cwu.elementFromPoint(aX, aY, true, true);
|
||||
|
||||
let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
|
||||
let HTMLFrameElement = Ci.nsIDOMHTMLFrameElement;
|
||||
while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
|
||||
let rect = elem.getBoundingClientRect();
|
||||
aX -= rect.left;
|
||||
aY -= rect.top;
|
||||
cwu = elem.contentDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
elem = cwu.elementFromPoint(aX, aY, true, true);
|
||||
}
|
||||
|
||||
return elem;
|
||||
},
|
||||
|
||||
getBoundingContentRect: function(aElement) {
|
||||
if (!aElement)
|
||||
return {x: 0, y: 0, w: 0, h: 0};
|
||||
|
||||
let document = aElement.ownerDocument;
|
||||
while (document.defaultView.frameElement)
|
||||
document = document.defaultView.frameElement.ownerDocument;
|
||||
|
||||
let cwu = document.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
let scrollX = {}, scrollY = {};
|
||||
cwu.getScrollXY(false, scrollX, scrollY);
|
||||
|
||||
let r = aElement.getBoundingClientRect();
|
||||
|
||||
// step out of iframes and frames, offsetting scroll values
|
||||
for (let frame = aElement.ownerDocument.defaultView; frame.frameElement && frame != content; frame = frame.parent) {
|
||||
// adjust client coordinates' origin to be top left of iframe viewport
|
||||
let rect = frame.frameElement.getBoundingClientRect();
|
||||
let left = frame.getComputedStyle(frame.frameElement, "").borderLeftWidth;
|
||||
let top = frame.getComputedStyle(frame.frameElement, "").borderTopWidth;
|
||||
scrollX.value += rect.left + parseInt(left);
|
||||
scrollY.value += rect.top + parseInt(top);
|
||||
}
|
||||
|
||||
return {x: r.left + scrollX.value,
|
||||
y: r.top + scrollY.value,
|
||||
w: r.width,
|
||||
h: r.height };
|
||||
}
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ include protocol POfflineCacheUpdate;
|
||||
include protocol PIndexedDB;
|
||||
|
||||
include "gfxMatrix.h";
|
||||
include "FrameMetrics.h";
|
||||
include "IPC/nsGUIEventIPC.h";
|
||||
include "mozilla/dom/TabMessageUtils.h";
|
||||
include "mozilla/dom/PermissionMessageUtils.h";
|
||||
@ -26,8 +27,10 @@ include DOMTypes;
|
||||
using IPC::URI;
|
||||
using IPC::Principal;
|
||||
using gfxMatrix;
|
||||
using gfxRect;
|
||||
using gfxSize;
|
||||
using mozilla::layers::LayersBackend;
|
||||
using mozilla::layers::FrameMetrics;
|
||||
using mozilla::layout::ScrollingBehavior;
|
||||
using mozilla::WindowsHandle;
|
||||
using nscolor;
|
||||
@ -249,6 +252,12 @@ parent:
|
||||
|
||||
NotifyDOMTouchListenerAdded();
|
||||
|
||||
/**
|
||||
* Instructs the TabParent to forward a request to zoom to a rect given in
|
||||
* CSS pixels. This rect is relative to the document.
|
||||
*/
|
||||
ZoomToRect(gfxRect aRect);
|
||||
|
||||
__delete__();
|
||||
|
||||
child:
|
||||
@ -267,10 +276,14 @@ child:
|
||||
|
||||
UpdateDimensions(nsRect rect, nsIntSize size);
|
||||
|
||||
UpdateFrame(nsIntRect displayPort,
|
||||
nsIntPoint scrollOffset,
|
||||
gfxSize resolution,
|
||||
nsIntRect screenSize);
|
||||
UpdateFrame(FrameMetrics frame);
|
||||
|
||||
/**
|
||||
* Requests handling of a double tap. |point| is in CSS pixels, relative to
|
||||
* the scroll offset. This message is expected to round-trip back to
|
||||
* ZoomToRect() with a rect indicating where we should zoom to.
|
||||
*/
|
||||
HandleDoubleTap(nsIntPoint point);
|
||||
|
||||
/**
|
||||
* Sending an activate message moves focus to the child.
|
||||
|
@ -126,6 +126,16 @@ TabChild::Observe(nsISupports *aSubject,
|
||||
if (tabChild == this) {
|
||||
mRemoteFrame->CancelDefaultPanZoom();
|
||||
}
|
||||
} else if (!strcmp(aTopic, "browser-zoom-to-rect")) {
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
||||
nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
|
||||
if (tabChild == this) {
|
||||
gfxRect rect;
|
||||
sscanf(NS_ConvertUTF16toUTF8(aData).get(),
|
||||
"{\"x\":%lf,\"y\":%lf,\"w\":%lf,\"h\":%lf}",
|
||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
SendZoomToRect(rect);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -157,6 +167,9 @@ TabChild::Init()
|
||||
observerService->AddObserver(this,
|
||||
"cancel-default-pan-zoom",
|
||||
false);
|
||||
observerService->AddObserver(this,
|
||||
"browser-zoom-to-rect",
|
||||
false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -682,41 +695,17 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
|
||||
const nsIntPoint& aScrollOffset,
|
||||
const gfxSize& aResolution,
|
||||
const nsIntRect& aScreenSize)
|
||||
void
|
||||
TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
|
||||
const nsACString& aJSONData)
|
||||
{
|
||||
if (!mCx || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", aScrollOffset.x);
|
||||
data += nsPrintfCString(", \"y\" : %d", aScrollOffset.y);
|
||||
// We don't treat the x and y scales any differently for this
|
||||
// semi-platform-specific code.
|
||||
data += nsPrintfCString(", \"zoom\" : %f", aResolution.width);
|
||||
data += nsPrintfCString(", \"displayPort\" : ");
|
||||
data += nsPrintfCString("{ \"left\" : %d", aDisplayPort.X());
|
||||
data += nsPrintfCString(", \"top\" : %d", aDisplayPort.Y());
|
||||
data += nsPrintfCString(", \"width\" : %d", aDisplayPort.Width());
|
||||
data += nsPrintfCString(", \"height\" : %d", aDisplayPort.Height());
|
||||
data += nsPrintfCString(", \"resolution\" : %f", aResolution.width);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(", \"screenSize\" : ");
|
||||
data += nsPrintfCString("{ \"width\" : %d", aScreenSize.width);
|
||||
data += nsPrintfCString(", \"height\" : %d", aScreenSize.height);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(" }");
|
||||
|
||||
JSAutoRequest ar(mCx);
|
||||
jsval json = JSVAL_NULL;
|
||||
StructuredCloneData cloneData;
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (JS_ParseJSON(mCx,
|
||||
static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()),
|
||||
data.Length(),
|
||||
static_cast<const jschar*>(NS_ConvertUTF8toUTF16(aJSONData).get()),
|
||||
aJSONData.Length(),
|
||||
&json)) {
|
||||
WriteStructuredClone(mCx, json, buffer, cloneData.mClosure);
|
||||
cloneData.mData = buffer.data();
|
||||
@ -729,8 +718,60 @@ TabChild::RecvUpdateFrame(const nsIntRect& aDisplayPort,
|
||||
nsRefPtr<nsFrameMessageManager> mm =
|
||||
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
|
||||
mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
|
||||
NS_LITERAL_STRING("Viewport:Change"), false,
|
||||
&cloneData, nullptr, nullptr);
|
||||
aMessageName, false, &cloneData, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
{
|
||||
if (!mCx || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", aFrameMetrics.mViewportScrollOffset.x);
|
||||
data += nsPrintfCString(", \"y\" : %d", aFrameMetrics.mViewportScrollOffset.y);
|
||||
// We don't treat the x and y scales any differently for this
|
||||
// semi-platform-specific code.
|
||||
data += nsPrintfCString(", \"zoom\" : %f", aFrameMetrics.mResolution.width);
|
||||
data += nsPrintfCString(", \"displayPort\" : ");
|
||||
data += nsPrintfCString("{ \"left\" : %d", aFrameMetrics.mDisplayPort.X());
|
||||
data += nsPrintfCString(", \"top\" : %d", aFrameMetrics.mDisplayPort.Y());
|
||||
data += nsPrintfCString(", \"width\" : %d", aFrameMetrics.mDisplayPort.Width());
|
||||
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mDisplayPort.Height());
|
||||
data += nsPrintfCString(", \"resolution\" : %f", aFrameMetrics.mResolution.width);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(", \"screenSize\" : ");
|
||||
data += nsPrintfCString("{ \"width\" : %d", aFrameMetrics.mViewport.width);
|
||||
data += nsPrintfCString(", \"height\" : %d", aFrameMetrics.mViewport.height);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(", \"cssPageRect\" : ");
|
||||
data += nsPrintfCString("{ \"x\" : %f", aFrameMetrics.mCSSContentRect.x);
|
||||
data += nsPrintfCString(", \"y\" : %f", aFrameMetrics.mCSSContentRect.y);
|
||||
data += nsPrintfCString(", \"width\" : %f", aFrameMetrics.mCSSContentRect.width);
|
||||
data += nsPrintfCString(", \"height\" : %f", aFrameMetrics.mCSSContentRect.height);
|
||||
data += nsPrintfCString(" }");
|
||||
data += nsPrintfCString(" }");
|
||||
|
||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvHandleDoubleTap(const nsIntPoint& aPoint)
|
||||
{
|
||||
if (!mCx || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", aPoint.x);
|
||||
data += nsPrintfCString(", \"y\" : %d", aPoint.y);
|
||||
data += nsPrintfCString(" }");
|
||||
|
||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "FrameMetrics.h"
|
||||
|
||||
struct gfxMatrix;
|
||||
|
||||
@ -172,10 +173,8 @@ public:
|
||||
virtual bool RecvLoadURL(const nsCString& uri);
|
||||
virtual bool RecvShow(const nsIntSize& size);
|
||||
virtual bool RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size);
|
||||
virtual bool RecvUpdateFrame(const nsIntRect& aDisplayPort,
|
||||
const nsIntPoint& aScrollOffset,
|
||||
const gfxSize& aResolution,
|
||||
const nsIntRect& aScreenSize);
|
||||
virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
|
||||
virtual bool RecvHandleDoubleTap(const nsIntPoint& aPoint);
|
||||
virtual bool RecvActivate();
|
||||
virtual bool RecvDeactivate();
|
||||
virtual bool RecvMouseEvent(const nsString& aType,
|
||||
@ -289,6 +288,14 @@ private:
|
||||
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
||||
void DoFakeShow();
|
||||
|
||||
// Wraps up a JSON object as a structured clone and sends it to the browser
|
||||
// chrome script.
|
||||
//
|
||||
// XXX/bug 780335: Do the work the browser chrome script does in C++ instead
|
||||
// so we don't need things like this.
|
||||
void DispatchMessageManagerMessage(const nsAString& aMessageName,
|
||||
const nsACString& aJSONData);
|
||||
|
||||
nsresult
|
||||
BrowserFrameProvideWindow(nsIDOMWindow* aOpener,
|
||||
nsIURI* aURI,
|
||||
|
@ -225,10 +225,12 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size)
|
||||
void
|
||||
TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
{
|
||||
unused << SendUpdateFrame(aFrameMetrics.mDisplayPort,
|
||||
aFrameMetrics.mViewportScrollOffset,
|
||||
aFrameMetrics.mResolution,
|
||||
aFrameMetrics.mViewport);
|
||||
unused << SendUpdateFrame(aFrameMetrics);
|
||||
}
|
||||
|
||||
void TabParent::HandleDoubleTap(const nsIntPoint& aPoint)
|
||||
{
|
||||
unused << SendHandleDoubleTap(aPoint);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1099,5 +1101,14 @@ TabParent::RecvNotifyDOMTouchListenerAdded()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvZoomToRect(const gfxRect& aRect)
|
||||
{
|
||||
if (RenderFrameParent* rfp = GetRenderFrame()) {
|
||||
rfp->ZoomToRect(aRect);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace tabs
|
||||
} // namespace mozilla
|
||||
|
@ -102,6 +102,7 @@ public:
|
||||
virtual bool RecvGetDPI(float* aValue);
|
||||
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
|
||||
virtual bool RecvNotifyDOMTouchListenerAdded();
|
||||
virtual bool RecvZoomToRect(const gfxRect& aRect);
|
||||
virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
|
||||
const nsCString& aName,
|
||||
const nsCString& aFeatures,
|
||||
@ -121,6 +122,7 @@ public:
|
||||
void Show(const nsIntSize& size);
|
||||
void UpdateDimensions(const nsRect& rect, const nsIntSize& size);
|
||||
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
|
||||
void HandleDoubleTap(const nsIntPoint& aPoint);
|
||||
void Activate();
|
||||
void Deactivate();
|
||||
|
||||
|
@ -6,15 +6,20 @@
|
||||
|
||||
#include "CompositorParent.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Constants.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/XPCOM.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "AsyncPanZoomController.h"
|
||||
#include "GestureEventListener.h"
|
||||
#include "nsIThreadManager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "Layers.h"
|
||||
#include "AnimationCommon.h"
|
||||
|
||||
using namespace mozilla::css;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -44,6 +49,26 @@ static const float MIN_SKATE_SPEED = 0.5f;
|
||||
*/
|
||||
static const float AXIS_LOCK_ANGLE = M_PI / 6.0;
|
||||
|
||||
/**
|
||||
* Duration of a zoom to animation.
|
||||
*/
|
||||
static const TimeDuration ZOOM_TO_DURATION = TimeDuration::FromSeconds(0.25);
|
||||
|
||||
/**
|
||||
* Computed time function used for sampling frames of a zoom to animation.
|
||||
*/
|
||||
StaticAutoPtr<ComputedTimingFunction> gComputedTimingFunction;
|
||||
|
||||
/**
|
||||
* Maximum zoom amount, always used, even if a page asks for higher.
|
||||
*/
|
||||
static const double MAX_ZOOM = 8.0;
|
||||
|
||||
/**
|
||||
* Minimum zoom amount, always used, even if a page asks for lower.
|
||||
*/
|
||||
static const double MIN_ZOOM = 0.125;
|
||||
|
||||
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
|
||||
GestureBehavior aGestures)
|
||||
: mGeckoContentController(aGeckoContentController),
|
||||
@ -62,6 +87,13 @@ AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoCon
|
||||
}
|
||||
|
||||
SetDPI(mDPI);
|
||||
|
||||
if (!gComputedTimingFunction) {
|
||||
gComputedTimingFunction = new ComputedTimingFunction();
|
||||
gComputedTimingFunction->Init(
|
||||
nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE));
|
||||
ClearOnShutdown(&gComputedTimingFunction);
|
||||
}
|
||||
}
|
||||
|
||||
AsyncPanZoomController::~AsyncPanZoomController() {
|
||||
@ -202,6 +234,12 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
|
||||
switch (mState) {
|
||||
case ANIMATING_ZOOM:
|
||||
// We just interrupted a double-tap animation, so force a redraw in case
|
||||
// this touchstart is just a tap that doesn't end up triggering a redraw.
|
||||
RequestContentRepaint();
|
||||
ScheduleComposite();
|
||||
// Fall through.
|
||||
case FLING:
|
||||
CancelAnimation();
|
||||
// Fall through.
|
||||
@ -231,6 +269,7 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
||||
switch (mState) {
|
||||
case FLING:
|
||||
case NOTHING:
|
||||
case ANIMATING_ZOOM:
|
||||
// May happen if the user double-taps and drags without lifting after the
|
||||
// second tap. Ignore the move if this happens.
|
||||
return nsEventStatus_eIgnore;
|
||||
@ -272,6 +311,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
||||
// Should never happen.
|
||||
NS_WARNING("Received impossible touch end in OnTouchEnd.");
|
||||
// Fall through.
|
||||
case ANIMATING_ZOOM:
|
||||
case NOTHING:
|
||||
// May happen if the user double-taps and drags without lifting after the
|
||||
// second tap. Ignore if this happens.
|
||||
@ -343,14 +383,14 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
||||
PRInt32 neededDisplacementX = 0, neededDisplacementY = 0;
|
||||
|
||||
// Only do the scaling if we won't go over 8x zoom in or out.
|
||||
bool doScale = (scale < 8.0f && spanRatio > 1.0f) || (scale > 0.125f && spanRatio < 1.0f);
|
||||
bool doScale = (scale < MAX_ZOOM && spanRatio > 1.0f) || (scale > MIN_ZOOM && spanRatio < 1.0f);
|
||||
|
||||
// If this zoom will take it over 8x zoom in either direction, but it's not
|
||||
// already there, then normalize it.
|
||||
if (scale * spanRatio > 8.0f) {
|
||||
spanRatio = scale / 8.0f;
|
||||
} else if (scale * spanRatio < 0.125f) {
|
||||
spanRatio = scale / 0.125f;
|
||||
if (scale * spanRatio > MAX_ZOOM) {
|
||||
spanRatio = scale / MAX_ZOOM;
|
||||
} else if (scale * spanRatio < MIN_ZOOM) {
|
||||
spanRatio = scale / MIN_ZOOM;
|
||||
}
|
||||
|
||||
if (doScale) {
|
||||
@ -435,7 +475,15 @@ nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput
|
||||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
|
||||
// XXX: Implement this.
|
||||
if (mGeckoContentController) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
gfx::Point point = WidgetSpaceToCompensatedViewportSpace(
|
||||
gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y),
|
||||
mFrameMetrics.mResolution.width);
|
||||
mGeckoContentController->HandleDoubleTap(nsIntPoint(NS_lround(point.x), NS_lround(point.y)));
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
@ -571,7 +619,7 @@ void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
|
||||
float scale = mFrameMetrics.mResolution.width;
|
||||
|
||||
// The page rect is the css page rect scaled by the current zoom.
|
||||
pageSize.ScaleRoundOut(scale);
|
||||
pageSize.ScaleRoundOut(1 / scale);
|
||||
|
||||
// Round the page rect so we don't get any truncation, then get the nsIntRect
|
||||
// from this.
|
||||
@ -743,9 +791,43 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
// If a fling is currently happening, apply it now. We can pull the updated
|
||||
// metrics afterwards.
|
||||
requestAnimationFrame = requestAnimationFrame || DoFling(aSampleTime - mLastSampleTime);
|
||||
switch (mState)
|
||||
{
|
||||
case FLING:
|
||||
// If a fling is currently happening, apply it now. We can pull the updated
|
||||
// metrics afterwards.
|
||||
requestAnimationFrame |= DoFling(aSampleTime - mLastSampleTime);
|
||||
break;
|
||||
case ANIMATING_ZOOM: {
|
||||
double animPosition = (aSampleTime - mAnimationStartTime) / ZOOM_TO_DURATION;
|
||||
if (animPosition > 1.0) {
|
||||
animPosition = 1.0;
|
||||
}
|
||||
double sampledPosition = gComputedTimingFunction->GetValue(animPosition);
|
||||
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
mEndZoomToMetrics.mResolution.width * sampledPosition +
|
||||
mStartZoomToMetrics.mResolution.width * (1 - sampledPosition);
|
||||
|
||||
mFrameMetrics.mViewportScrollOffset = nsIntPoint(
|
||||
mEndZoomToMetrics.mViewportScrollOffset.x * sampledPosition +
|
||||
mStartZoomToMetrics.mViewportScrollOffset.x * (1 - sampledPosition),
|
||||
mEndZoomToMetrics.mViewportScrollOffset.y * sampledPosition +
|
||||
mStartZoomToMetrics.mViewportScrollOffset.y * (1 - sampledPosition)
|
||||
);
|
||||
|
||||
requestAnimationFrame = true;
|
||||
|
||||
if (aSampleTime - mAnimationStartTime >= ZOOM_TO_DURATION) {
|
||||
mState = NOTHING;
|
||||
RequestContentRepaint();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Current local transform; this is not what's painted but rather what PZC has
|
||||
// transformed due to touches like panning or pinching. Eventually, the root
|
||||
@ -815,7 +897,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
// Assuming a first paint means a new page has been loaded, clear the flag
|
||||
// indicating that we may have touch listeners.
|
||||
mMayHaveTouchListeners = false;
|
||||
} else if (!mFrameMetrics.mContentRect.IsEqualEdges(aViewportFrame.mContentRect)) {
|
||||
} else if (!mFrameMetrics.mCSSContentRect.IsEqualEdges(aViewportFrame.mCSSContentRect)) {
|
||||
mFrameMetrics.mCSSContentRect = aViewportFrame.mCSSContentRect;
|
||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
||||
}
|
||||
@ -844,6 +926,80 @@ void AsyncPanZoomController::CancelDefaultPanZoom() {
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
||||
gfx::Rect zoomToRect(gfx::Rect(aRect.x, aRect.y, aRect.width, aRect.height));
|
||||
gfx::Rect cssPageRect = mFrameMetrics.mCSSContentRect;
|
||||
|
||||
SetState(ANIMATING_ZOOM);
|
||||
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
nsIntRect viewport = mFrameMetrics.mViewport;
|
||||
|
||||
// If the rect is empty, treat it as a request to zoom out to the full page
|
||||
// size.
|
||||
if (zoomToRect.IsEmpty()) {
|
||||
nsIntRect cssViewport = viewport;
|
||||
cssViewport.ScaleRoundIn(1 / mFrameMetrics.mResolution.width);
|
||||
cssViewport.MoveBy(mFrameMetrics.mViewportScrollOffset);
|
||||
|
||||
float y = mFrameMetrics.mViewportScrollOffset.y;
|
||||
float newHeight = cssViewport.height * cssPageRect.width / cssViewport.width;
|
||||
float dh = cssViewport.height - newHeight;
|
||||
|
||||
zoomToRect = gfx::Rect(0.0f,
|
||||
y + dh/2,
|
||||
cssPageRect.width,
|
||||
y + dh/2 + newHeight);
|
||||
} else {
|
||||
float targetRatio = float(viewport.width) / float(viewport.height);
|
||||
float rectRatio = zoomToRect.width / zoomToRect.height;
|
||||
|
||||
if (fabsf(targetRatio - rectRatio) < EPSILON) {
|
||||
// All good, do nothing.
|
||||
} else if (targetRatio < rectRatio) {
|
||||
// Need to increase zoomToRect height.
|
||||
float newHeight = zoomToRect.height / targetRatio;
|
||||
zoomToRect.y -= (newHeight - zoomToRect.height) / 2;
|
||||
zoomToRect.height = newHeight;
|
||||
} else { // (targetRatio > rectRatio) {
|
||||
// Need to increase zoomToRect width.
|
||||
float newWidth = targetRatio * zoomToRect.width;
|
||||
zoomToRect.x -= (newWidth - zoomToRect.width) / 2;
|
||||
zoomToRect.width = newWidth;
|
||||
}
|
||||
|
||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||
}
|
||||
|
||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
||||
NS_MIN(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
|
||||
|
||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
||||
clamped(mEndZoomToMetrics.mResolution.width, MIN_ZOOM, MAX_ZOOM);
|
||||
|
||||
// Recalculate the zoom to rect using the new dimensions.
|
||||
zoomToRect.width = viewport.width / mEndZoomToMetrics.mResolution.width;
|
||||
zoomToRect.height = viewport.height / mEndZoomToMetrics.mResolution.height;
|
||||
|
||||
// Clamp the zoom to rect to the CSS rect to make sure it fits.
|
||||
zoomToRect = zoomToRect.Intersect(cssPageRect);
|
||||
|
||||
// Do one final recalculation to get the resolution.
|
||||
mEndZoomToMetrics.mResolution.width = mEndZoomToMetrics.mResolution.height =
|
||||
NS_MAX(viewport.width / zoomToRect.width, viewport.height / zoomToRect.height);
|
||||
|
||||
mStartZoomToMetrics = mFrameMetrics;
|
||||
mEndZoomToMetrics.mViewportScrollOffset =
|
||||
nsIntPoint(NS_lround(zoomToRect.x), NS_lround(zoomToRect.y));
|
||||
|
||||
mAnimationStartTime = TimeStamp::Now();
|
||||
|
||||
ScheduleComposite();
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetState(PanZoomState aState) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
mState = aState;
|
||||
|
@ -119,6 +119,13 @@ public:
|
||||
*/
|
||||
void CancelDefaultPanZoom();
|
||||
|
||||
/**
|
||||
* Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
|
||||
* in. The actual animation is done on the compositor thread after being set
|
||||
* up. |aRect| must be given in CSS pixels, relative to the document.
|
||||
*/
|
||||
void ZoomToRect(const gfxRect& aRect);
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// These methods must only be called on the compositor thread.
|
||||
//
|
||||
@ -368,6 +375,7 @@ private:
|
||||
TOUCHING, /* one touch-start event received */
|
||||
PANNING, /* panning without axis lock */
|
||||
PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */
|
||||
ANIMATING_ZOOM /* animated zoom to a new rect */
|
||||
};
|
||||
|
||||
enum ContentPainterStatus {
|
||||
@ -411,6 +419,16 @@ private:
|
||||
// If we don't do this check, we don't get a ShadowLayersUpdated back.
|
||||
FrameMetrics mLastPaintRequestMetrics;
|
||||
|
||||
// Old metrics from before we started a zoom animation. This is only valid
|
||||
// when we are in the "ANIMATED_ZOOM" state. This is used so that we can
|
||||
// interpolate between the start and end frames. We only use the
|
||||
// |mViewportScrollOffset| and |mResolution| fields on this.
|
||||
FrameMetrics mStartZoomToMetrics;
|
||||
// Target metrics for a zoom to animation. This is only valid when we are in
|
||||
// the "ANIMATED_ZOOM" state. We only use the |mViewportScrollOffset| and
|
||||
// |mResolution| fields on this.
|
||||
FrameMetrics mEndZoomToMetrics;
|
||||
|
||||
AxisX mX;
|
||||
AxisY mY;
|
||||
|
||||
@ -426,6 +444,10 @@ private:
|
||||
// The last time a touch event came through on the UI thread.
|
||||
PRInt32 mLastEventTime;
|
||||
|
||||
// Start time of an animation. This is used for a zoom to animation to mark
|
||||
// the beginning.
|
||||
TimeStamp mAnimationStartTime;
|
||||
|
||||
// Stores the previous focus point if there is a pinch gesture happening. Used
|
||||
// to allow panning by moving multiple fingers (thus moving the focus point).
|
||||
nsIntPoint mLastZoomFocus;
|
||||
|
@ -23,6 +23,14 @@ public:
|
||||
*/
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
|
||||
|
||||
/**
|
||||
* Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
|
||||
* the current scroll offset. This should eventually round-trip back to
|
||||
* AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
|
||||
* to.
|
||||
*/
|
||||
virtual void HandleDoubleTap(const nsIntPoint& aPoint) = 0;
|
||||
|
||||
GeckoContentController() {}
|
||||
virtual ~GeckoContentController() {}
|
||||
};
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define IPC_ShadowLayerUtils_h
|
||||
|
||||
#include "IPC/IPCMessageUtils.h"
|
||||
#include "FrameMetrics.h"
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/WidgetUtils.h"
|
||||
|
||||
@ -39,34 +38,6 @@ struct MagicGrallocBufferHandle {
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCSSContentRect);
|
||||
WriteParam(aMsg, aParam.mViewport);
|
||||
WriteParam(aMsg, aParam.mContentRect);
|
||||
WriteParam(aMsg, aParam.mViewportScrollOffset);
|
||||
WriteParam(aMsg, aParam.mDisplayPort);
|
||||
WriteParam(aMsg, aParam.mScrollId);
|
||||
WriteParam(aMsg, aParam.mResolution);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return (ReadParam(aMsg, aIter, &aResult->mCSSContentRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mViewport) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mContentRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mResolution));
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(MOZ_HAVE_SURFACEDESCRIPTORX11)
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
|
||||
|
@ -23,11 +23,13 @@
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxPattern.h"
|
||||
#include "gfxPoint.h"
|
||||
#include "gfxRect.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsRegion.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "jsapi.h"
|
||||
#include "LayersTypes.h"
|
||||
#include "FrameMetrics.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4800 )
|
||||
@ -517,6 +519,28 @@ struct ParamTraits<gfxSize>
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<gfxRect>
|
||||
{
|
||||
typedef gfxRect paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.x);
|
||||
WriteParam(aMsg, aParam.y);
|
||||
WriteParam(aMsg, aParam.width);
|
||||
WriteParam(aMsg, aParam.height);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return ReadParam(aMsg, aIter, &aResult->x) &&
|
||||
ReadParam(aMsg, aIter, &aResult->y) &&
|
||||
ReadParam(aMsg, aIter, &aResult->width) &&
|
||||
ReadParam(aMsg, aIter, &aResult->height);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<gfx3DMatrix>
|
||||
{
|
||||
@ -902,6 +926,34 @@ struct ParamTraits<mozilla::SerializedStructuredCloneBuffer>
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::layers::FrameMetrics>
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
WriteParam(aMsg, aParam.mCSSContentRect);
|
||||
WriteParam(aMsg, aParam.mViewport);
|
||||
WriteParam(aMsg, aParam.mContentRect);
|
||||
WriteParam(aMsg, aParam.mViewportScrollOffset);
|
||||
WriteParam(aMsg, aParam.mDisplayPort);
|
||||
WriteParam(aMsg, aParam.mScrollId);
|
||||
WriteParam(aMsg, aParam.mResolution);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
return (ReadParam(aMsg, aIter, &aResult->mCSSContentRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mViewport) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mContentRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mResolution));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace IPC */
|
||||
|
||||
#endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */
|
||||
|
@ -492,6 +492,23 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void HandleDoubleTap(const nsIntPoint& aPoint) MOZ_OVERRIDE
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
// We have to send this message from the "UI thread" (main
|
||||
// thread).
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap,
|
||||
aPoint));
|
||||
return;
|
||||
}
|
||||
if (mRenderFrame) {
|
||||
TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
|
||||
browser->HandleDoubleTap(aPoint);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearRenderFrame() { mRenderFrame = nullptr; }
|
||||
|
||||
private:
|
||||
@ -869,6 +886,14 @@ RenderFrameParent::NotifyDOMTouchListenerAdded()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RenderFrameParent::ZoomToRect(const gfxRect& aRect)
|
||||
{
|
||||
if (mPanZoomController) {
|
||||
mPanZoomController->ZoomToRect(aRect);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layout
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -95,6 +95,8 @@ public:
|
||||
|
||||
void NotifyDOMTouchListenerAdded();
|
||||
|
||||
void ZoomToRect(const gfxRect& aRect);
|
||||
|
||||
protected:
|
||||
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user