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()); }
static void MaybeAlignAndClampDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics, const CSSPoint& aActualScrollOffset) { // Correct the display-port by the difference between the requested scroll // offset and the resulting scroll offset after setting the requested value. CSSRect& displayPort = aFrameMetrics.mDisplayPort; displayPort += aFrameMetrics.mScrollOffset - aActualScrollOffset; // Expand the display port to the next tile boundaries, if tiled thebes layers // are enabled. if (gfxPlatform::GetPrefLayersEnableTiles()) { displayPort = ExpandDisplayPortToTileBoundaries(displayPort + aActualScrollOffset, aFrameMetrics.LayersPixelsPerCSSPixel()) - aActualScrollOffset; } // Finally, clamp the display port to the expanded scrollable rect. CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect(); displayPort = scrollableRect.Intersect(displayPort + aActualScrollOffset) - aActualScrollOffset; }
void CheckerboardEvent::LogInfo(RendertraceProperty aProperty, const TimeStamp& aTimestamp, const CSSRect& aRect, const std::string& aExtraInfo, const MonitorAutoLock& aProofOfLock) { MOZ_ASSERT(mRecordTrace); if (mRendertraceInfo.tellp() >= LOG_LENGTH_LIMIT) { // The log is already long enough, don't put more things into it. We'll // append a truncation message when this event ends. return; } // The log is consumed by the page at // http://people.mozilla.org/~kgupta/rendertrace.html and will move to // about:checkerboard in bug 1238042. The format is not formally specced, but // an informal description can be found at // https://github.com/staktrace/rendertrace/blob/master/index.html#L30 mRendertraceInfo << "RENDERTRACE " << (aTimestamp - mOriginTime).ToMilliseconds() << " rect " << sColors[aProperty] << " " << aRect.X() << " " << aRect.Y() << " " << aRect.Width() << " " << aRect.Height() << " " << "// " << sDescriptions[aProperty] << aExtraInfo << std::endl; }
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); }
static float GetDisplayportCoverage(const CSSRect& aDisplayPort, const Matrix4x4& aTransformToScreen, const IntRect& aScreenRect) { Rect transformedDisplayport = aTransformToScreen.TransformBounds(aDisplayPort.ToUnknownRect()); transformedDisplayport.RoundOut(); IntRect displayport = IntRect(transformedDisplayport.x, transformedDisplayport.y, transformedDisplayport.width, transformedDisplayport.height); if (!displayport.Contains(aScreenRect)) { nsIntRegion coveredRegion; coveredRegion.And(aScreenRect, displayport); return coveredRegion.Area() / (float)(aScreenRect.width * aScreenRect.height); } return 1.0f; }
CSSRect CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& 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(metrics.GetScrollOffset(), 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.y + rect.height)) { rect.y += rect.height - targetHeight; } else if (newY > rect.y) { rect.y = newY; } rect.height = 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.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; }