void AndroidGeckoLayerClient::SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset) { NS_ASSERTION(!isNull(), "SyncFrameMetrics called on null layer client!"); JNIEnv *env = GetJNIForThread(); // this is called on the compositor thread if (!env) return; AutoLocalJNIFrame jniFrame(env); // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels LayerRect dpUnrounded = aDisplayPort * aDisplayResolution; dpUnrounded += LayerPoint::FromUnknownPoint(aScrollOffset.ToUnknownPoint()); LayerIntRect dp = gfx::RoundedToInt(dpUnrounded); jobject viewTransformJObj = env->CallObjectMethod(wrapped_obj, jSyncFrameMetricsMethod, aScrollOffset.x, aScrollOffset.y, aZoom, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(), aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale, aIsFirstPaint); if (jniFrame.CheckForException()) return; NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!"); AndroidViewTransform viewTransform; viewTransform.Init(viewTransformJObj); viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins); aOffset.x = viewTransform.GetOffsetX(env); aOffset.y = viewTransform.GetOffsetY(env); }
void AndroidCompositorWidget::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, const CSSToParentLayerScale& aZoom, const CSSRect& aCssPageRect, const CSSRect& aDisplayPort, const CSSToLayerScale& aPaintedResolution, bool aLayersUpdated, int32_t aPaintSyncId, ScreenMargin& aFixedLayerMargins) { auto layerClient = static_cast<nsWindow*>(RealWidget())->GetLayerClient(); if (!layerClient) { return; } // convert the displayport rect from document-relative CSS pixels to // document-relative device pixels LayerIntRect dp = gfx::RoundedToInt(aDisplayPort * aPaintedResolution); java::ViewTransform::LocalRef viewTransform = layerClient->SyncFrameMetrics( aScrollOffset.x, aScrollOffset.y, aZoom.scale, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(), dp.x, dp.y, dp.width, dp.height, aPaintedResolution.scale, aLayersUpdated, aPaintSyncId); MOZ_ASSERT(viewTransform, "No view transform object!"); aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop(); aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight(); aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom(); aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft(); }
void AndroidGeckoLayerClient::SetPageRect(const CSSRect& aCssPageRect) { NS_ASSERTION(!isNull(), "SetPageRect called on null layer client!"); JNIEnv *env = GetJNIForThread(); // this is called on the compositor thread if (!env) return; AutoLocalJNIFrame jniFrame(env, 0); return env->CallVoidMethod(wrapped_obj, jSetPageRect, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost()); }
void AndroidGeckoLayerClient::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect) { NS_ASSERTION(!isNull(), "SetFirstPaintViewport called on null layer client!"); JNIEnv *env = GetJNIForThread(); // this is called on the compositor thread if (!env) return; AutoLocalJNIFrame jniFrame(env, 0); return env->CallVoidMethod(wrapped_obj, jSetFirstPaintViewport, (float)aOffset.x, (float)aOffset.y, aZoom.scale, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost()); }
void AndroidCompositorWidget::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect) { auto layerClient = static_cast<nsWindow*>(RealWidget())->GetLayerClient(); if (!layerClient) { return; } layerClient->SetFirstPaintViewport( float(aOffset.x), float(aOffset.y), aZoom.scale, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost()); }
CSSRect CalculateRectToZoomTo(const RefPtr<dom::Document>& aRootContentDocument, const CSSPoint& aPoint) { // Ensure the layout information we get is up-to-date. aRootContentDocument->FlushPendingNotifications(FlushType::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( CSSPoint::FromAppUnits(shell->GetVisualViewportOffset()), metrics.CalculateCompositedSizeInCssPixels()); const CSSCoord margin = 15; CSSRect rect = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame); // If the element is taller than the visible area of the page scale // the height of the |rect| so that it has the same aspect ratio as // the root frame. The clipped |rect| is centered on the y value of // the touch point. This allows tall narrow elements to be zoomed. if (!rect.IsEmpty() && compositedArea.Width() > 0.0f) { const float widthRatio = rect.Width() / compositedArea.Width(); float targetHeight = compositedArea.Height() * widthRatio; if (widthRatio < 0.9 && targetHeight < rect.Height()) { const CSSPoint scrollPoint = CSSPoint::FromAppUnits(rootScrollFrame->GetScrollPosition()); float newY = aPoint.y + scrollPoint.y - (targetHeight * 0.5f); if ((newY + targetHeight) > rect.YMost()) { rect.MoveByY(rect.Height() - targetHeight); } else if (newY > rect.Y()) { rect.MoveToY(newY); } rect.SetHeight(targetHeight); } } 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.SetWidth( 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.MoveToY(cssTapY - (rounded.Height() / 2)); } return rounded; }