mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1131359 - Port the double-tap-to-zoom functionality of BrowserElementPanning.js to C++. r=kats
This commit is contained in:
parent
e4fa0cf8ea
commit
7c2c79296f
@ -27,6 +27,7 @@
|
||||
#include "mozilla/layers/APZCTreeManager.h"
|
||||
#include "mozilla/layers/APZEventState.h"
|
||||
#include "mozilla/layers/CompositorChild.h"
|
||||
#include "mozilla/layers/DoubleTapToZoom.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "mozilla/layout/RenderFrameChild.h"
|
||||
@ -116,7 +117,6 @@ NS_IMPL_ISUPPORTS(ContentListener, nsIDOMEventListener)
|
||||
|
||||
static const CSSSize kDefaultViewportSize(980, 480);
|
||||
|
||||
static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
|
||||
static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
|
||||
|
||||
typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
|
||||
@ -283,39 +283,6 @@ TabChildBase::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
|
||||
FrameMetrics newMetrics = aFrameMetrics;
|
||||
APZCCallbackHelper::UpdateRootFrame(newMetrics);
|
||||
|
||||
CSSSize cssCompositedSize = newMetrics.CalculateCompositedSizeInCssPixels();
|
||||
// The BrowserElementScrolling helper must know about these updated metrics
|
||||
// for other functions it performs, such as double tap handling.
|
||||
// Note, %f must not be used because it is locale specific!
|
||||
nsString data;
|
||||
data.AppendPrintf("{ \"x\" : %d", NS_lround(newMetrics.GetScrollOffset().x));
|
||||
data.AppendPrintf(", \"y\" : %d", NS_lround(newMetrics.GetScrollOffset().y));
|
||||
data.AppendLiteral(", \"viewport\" : ");
|
||||
data.AppendLiteral("{ \"width\" : ");
|
||||
data.AppendFloat(newMetrics.GetViewport().width);
|
||||
data.AppendLiteral(", \"height\" : ");
|
||||
data.AppendFloat(newMetrics.GetViewport().height);
|
||||
data.AppendLiteral(" }");
|
||||
data.AppendLiteral(", \"cssPageRect\" : ");
|
||||
data.AppendLiteral("{ \"x\" : ");
|
||||
data.AppendFloat(newMetrics.GetScrollableRect().x);
|
||||
data.AppendLiteral(", \"y\" : ");
|
||||
data.AppendFloat(newMetrics.GetScrollableRect().y);
|
||||
data.AppendLiteral(", \"width\" : ");
|
||||
data.AppendFloat(newMetrics.GetScrollableRect().width);
|
||||
data.AppendLiteral(", \"height\" : ");
|
||||
data.AppendFloat(newMetrics.GetScrollableRect().height);
|
||||
data.AppendLiteral(" }");
|
||||
data.AppendLiteral(", \"cssCompositedRect\" : ");
|
||||
data.AppendLiteral("{ \"width\" : ");
|
||||
data.AppendFloat(cssCompositedSize.width);
|
||||
data.AppendLiteral(", \"height\" : ");
|
||||
data.AppendFloat(cssCompositedSize.height);
|
||||
data.AppendLiteral(" }");
|
||||
data.AppendLiteral(" }");
|
||||
|
||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -638,23 +605,7 @@ TabChild::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData)
|
||||
{
|
||||
if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
|
||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
|
||||
nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
|
||||
if (tabChild == this) {
|
||||
nsCOMPtr<nsIDocument> doc(GetDocument());
|
||||
uint32_t presShellId;
|
||||
ViewID viewId;
|
||||
if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(doc->GetDocumentElement(),
|
||||
&presShellId, &viewId)) {
|
||||
CSSRect rect;
|
||||
sscanf(NS_ConvertUTF16toUTF8(aData).get(),
|
||||
"{\"x\":%f,\"y\":%f,\"w\":%f,\"h\":%f}",
|
||||
&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
SendZoomToRect(presShellId, viewId, rect);
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
|
||||
if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
|
||||
if (AsyncPanZoomEnabled()) {
|
||||
nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
|
||||
nsCOMPtr<nsIDocument> doc(GetDocument());
|
||||
@ -1764,14 +1715,18 @@ TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifier
|
||||
// Note: there is nothing to do with the modifiers here, as we are not
|
||||
// synthesizing any sort of mouse event.
|
||||
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
|
||||
nsString data;
|
||||
data.AppendLiteral("{ \"x\" : ");
|
||||
data.AppendFloat(point.x);
|
||||
data.AppendLiteral(", \"y\" : ");
|
||||
data.AppendFloat(point.y);
|
||||
data.AppendLiteral(" }");
|
||||
|
||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
|
||||
nsCOMPtr<nsIDocument> document = GetDocument();
|
||||
CSSRect zoomToRect = CalculateRectToZoomTo(document, point);
|
||||
// The double-tap can be dispatched by any scroll frame (so |aGuid| could be
|
||||
// the guid of any scroll frame), but the zoom-to-rect operation must be
|
||||
// performed by the root content scroll frame, so query its identifiers
|
||||
// for the SendZoomToRect() call rather than using the ones from |aGuid|.
|
||||
uint32_t presShellId;
|
||||
ViewID viewId;
|
||||
if (APZCCallbackHelper::GetOrCreateScrollIdentifiers(
|
||||
document->GetDocumentElement(), &presShellId, &viewId)) {
|
||||
SendZoomToRect(presShellId, viewId, zoomToRect);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2454,7 +2409,6 @@ TabChild::RecvDestroy()
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
|
||||
observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
|
||||
|
||||
const nsAttrValue::EnumTable* table =
|
||||
@ -2656,9 +2610,6 @@ TabChild::InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIden
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this,
|
||||
BROWSER_ZOOM_TO_RECT,
|
||||
false);
|
||||
observerService->AddObserver(this,
|
||||
BEFORE_FIRST_PAINT,
|
||||
false);
|
||||
|
178
gfx/layers/apz/util/DoubleTapToZoom.cpp
Normal file
178
gfx/layers/apz/util/DoubleTapToZoom.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/* -*- 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 "DoubleTapToZoom.h"
|
||||
|
||||
#include <algorithm> // for std::min, std::max
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMHTMLLIElement.h"
|
||||
#include "nsIDOMHTMLQuoteElement.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIFrameInlines.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
// Returns the DOM element found at |aPoint|, interpreted as being relative to
|
||||
// the root frame of |aShell|. If the point is inside a subdocument, returns
|
||||
// an element inside the subdocument, rather than the subdocument element
|
||||
// (and does so recursively).
|
||||
// The implementation was adapted from nsDocument::ElementFromPoint(), with
|
||||
// the notable exception that we don't pass nsLayoutUtils::IGNORE_CROSS_DOC
|
||||
// to GetFrameForPoint(), so as to get the behaviour described above in the
|
||||
// presence of subdocuments.
|
||||
static already_AddRefed<dom::Element>
|
||||
ElementFromPoint(const nsCOMPtr<nsIPresShell>& aShell,
|
||||
const CSSPoint& aPoint)
|
||||
{
|
||||
if (nsIFrame* rootFrame = aShell->GetRootFrame()) {
|
||||
if (nsIFrame* frame = nsLayoutUtils::GetFrameForPoint(rootFrame,
|
||||
CSSPoint::ToAppUnits(aPoint),
|
||||
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
|
||||
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME)) {
|
||||
while (frame && (!frame->GetContent() || frame->GetContent()->IsInAnonymousSubtree())) {
|
||||
frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
|
||||
}
|
||||
nsIContent* content = frame->GetContent();
|
||||
if (content && !content->IsElement()) {
|
||||
content = content->GetParent();
|
||||
}
|
||||
if (content) {
|
||||
nsCOMPtr<dom::Element> result = content->AsElement();
|
||||
return result.forget();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
ShouldZoomToElement(const nsCOMPtr<dom::Element>& aElement) {
|
||||
if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
|
||||
if (frame->GetDisplay() == NS_STYLE_DISPLAY_INLINE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (aElement->IsAnyOfHTMLElements(nsGkAtoms::li, nsGkAtoms::q)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the bounding rect of |aElement|, relative to the origin
|
||||
// of the document associated with |aShell|.
|
||||
// |aRootScrollFrame| should be the root scroll frame of the document in
|
||||
// question.
|
||||
// The implementation is adapted from Element::GetBoundingClientRect().
|
||||
static CSSRect
|
||||
GetBoundingContentRect(const nsCOMPtr<nsIPresShell>& aShell,
|
||||
const nsCOMPtr<dom::Element>& aElement,
|
||||
const nsIScrollableFrame* aRootScrollFrame) {
|
||||
if (nsIFrame* frame = aElement->GetPrimaryFrame()) {
|
||||
return CSSRect::FromAppUnits(
|
||||
nsLayoutUtils::GetAllInFlowRectsUnion(
|
||||
frame,
|
||||
aShell->GetRootFrame(),
|
||||
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS)
|
||||
+ aRootScrollFrame->GetScrollPosition());
|
||||
}
|
||||
return CSSRect();
|
||||
}
|
||||
|
||||
static bool
|
||||
IsRectZoomedIn(const CSSRect& aRect, const CSSRect& aCompositedArea)
|
||||
{
|
||||
// This functions checks to see if the area of the rect visible in the
|
||||
// composition bounds (i.e. the overlapArea variable below) is approximately
|
||||
// the max area of the rect we can show.
|
||||
CSSRect overlap = aCompositedArea.Intersect(aRect);
|
||||
float overlapArea = overlap.width * overlap.height;
|
||||
float availHeight = std::min(aRect.width * aCompositedArea.height / aCompositedArea.width,
|
||||
aRect.height);
|
||||
float showing = overlapArea / (aRect.width * availHeight);
|
||||
float ratioW = aRect.width / aCompositedArea.width;
|
||||
float ratioH = aRect.height / aCompositedArea.height;
|
||||
|
||||
return showing > 0.9 && (ratioW > 0.9 || ratioH > 0.9);
|
||||
}
|
||||
|
||||
CSSRect
|
||||
CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& aRootContentDocument,
|
||||
const CSSPoint& aPoint)
|
||||
{
|
||||
// Ensure the layout information we get is up-to-date.
|
||||
aRootContentDocument->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// An empty rect as return value is interpreted as "zoom out".
|
||||
const CSSRect zoomOut;
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = aRootContentDocument->GetShell();
|
||||
if (!shell) {
|
||||
return zoomOut;
|
||||
}
|
||||
|
||||
nsIScrollableFrame* rootScrollFrame = shell->GetRootScrollFrameAsScrollable();
|
||||
if (!rootScrollFrame) {
|
||||
return zoomOut;
|
||||
}
|
||||
|
||||
nsCOMPtr<dom::Element> element = ElementFromPoint(shell, aPoint);
|
||||
if (!element) {
|
||||
return zoomOut;
|
||||
}
|
||||
|
||||
while (element && !ShouldZoomToElement(element)) {
|
||||
element = element->GetParentElement();
|
||||
}
|
||||
|
||||
if (!element) {
|
||||
return zoomOut;
|
||||
}
|
||||
|
||||
FrameMetrics metrics = nsLayoutUtils::CalculateBasicFrameMetrics(rootScrollFrame);
|
||||
CSSRect compositedArea(metrics.GetScrollOffset(), metrics.CalculateCompositedSizeInCssPixels());
|
||||
const CSSCoord margin = 15;
|
||||
CSSRect rect = GetBoundingContentRect(shell, element, rootScrollFrame);
|
||||
rect = CSSRect(std::max(metrics.GetScrollableRect().x, rect.x - margin),
|
||||
rect.y,
|
||||
rect.width + 2 * margin,
|
||||
rect.height);
|
||||
// Constrict the rect to the screen's right edge
|
||||
rect.width = std::min(rect.width, metrics.GetScrollableRect().XMost() - rect.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 (IsRectZoomedIn(rect, compositedArea)) {
|
||||
return zoomOut;
|
||||
}
|
||||
|
||||
CSSRect rounded(rect);
|
||||
rounded.Round();
|
||||
|
||||
// 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 the page when double-tapping
|
||||
// to zoom in (bug 761721). The 1.2 multiplier is just a little fuzz to
|
||||
// compensate for 'rect' including horizontal margins but not vertical ones.
|
||||
CSSCoord cssTapY = metrics.GetScrollOffset().y + aPoint.y;
|
||||
if ((rect.height > rounded.height) && (cssTapY > rounded.y + (rounded.height * 1.2))) {
|
||||
rounded.y = cssTapY - (rounded.height / 2);
|
||||
}
|
||||
|
||||
return rounded;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
29
gfx/layers/apz/util/DoubleTapToZoom.h
Normal file
29
gfx/layers/apz/util/DoubleTapToZoom.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* -*- 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 mozilla_layers_DoubleTapToZoom_h
|
||||
#define mozilla_layers_DoubleTapToZoom_h
|
||||
|
||||
#include "Units.h"
|
||||
|
||||
class nsIDocument;
|
||||
template<class T> class nsCOMPtr;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* For a double tap at |aPoint|, return the rect to which the browser
|
||||
* should zoom in response, or an empty rect if the browser should zoom out.
|
||||
* |aDocument| should be the root content document for the content that was
|
||||
* tapped.
|
||||
*/
|
||||
CSSRect CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& aRootContentDocument,
|
||||
const CSSPoint& aPoint);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* mozilla_layers_DoubleTapToZoom_h */
|
@ -104,6 +104,7 @@ EXPORTS.mozilla.layers += [
|
||||
'apz/util/APZEventState.h',
|
||||
'apz/util/APZThreadUtils.h',
|
||||
'apz/util/ChromeProcessController.h',
|
||||
'apz/util/DoubleTapToZoom.h',
|
||||
'apz/util/InputAPZContext.h',
|
||||
'AtomicRefCountedWithFinalize.h',
|
||||
'AxisPhysicsModel.h',
|
||||
@ -247,6 +248,7 @@ UNIFIED_SOURCES += [
|
||||
'apz/util/APZEventState.cpp',
|
||||
'apz/util/APZThreadUtils.cpp',
|
||||
'apz/util/ChromeProcessController.cpp',
|
||||
'apz/util/DoubleTapToZoom.cpp',
|
||||
'apz/util/InputAPZContext.cpp',
|
||||
'AxisPhysicsModel.cpp',
|
||||
'AxisPhysicsMSDModel.cpp',
|
||||
@ -384,6 +386,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
||||
LOCAL_INCLUDES += [
|
||||
'/docshell/base', # for nsDocShell.h
|
||||
'/layout/base', # for TouchManager.h
|
||||
'/layout/generic', # for nsTextFrame.h
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -164,6 +164,11 @@ struct CSSPixel {
|
||||
NSAppUnitsToFloatPixels(aPoint.y, float(AppUnitsPerCSSPixel())));
|
||||
}
|
||||
|
||||
static CSSSize FromAppUnits(const nsSize& aSize) {
|
||||
return CSSSize(NSAppUnitsToFloatPixels(aSize.width, float(AppUnitsPerCSSPixel())),
|
||||
NSAppUnitsToFloatPixels(aSize.height, float(AppUnitsPerCSSPixel())));
|
||||
}
|
||||
|
||||
static CSSRect FromAppUnits(const nsRect& aRect) {
|
||||
return CSSRect(NSAppUnitsToFloatPixels(aRect.x, float(AppUnitsPerCSSPixel())),
|
||||
NSAppUnitsToFloatPixels(aRect.y, float(AppUnitsPerCSSPixel())),
|
||||
|
Loading…
Reference in New Issue
Block a user