/* 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/. */
using layers::APZCCallbackHelper; using layers::InputAPZContext; using layers::ScrollableLayerGuid;
template <typename Units>
gfx::Matrix4x4TypedFlagged<Units, Units>
ViewportUtils::GetVisualToLayoutTransform(nsIContent* aContent) {
static_assert(
std::is_same_v<Units, CSSPixel> ||
std::is_same_v<Units, LayoutDevicePixel>, "GetCallbackTransform() may only be used with CSS or LayoutDevice units");
if (!aContent || !aContent->GetPrimaryFrame()) { return {};
}
// First, scale inversely by the root content document's pres shell // resolution to cancel the scale-to-resolution transform that the // compositor adds to the layer with the pres shell resolution. The points // sent to Gecko by APZ don't have this transform unapplied (unlike other // compositor-side transforms) because Gecko needs it applied when hit // testing against content that's conceptually outside the resolution, // such as scrollbars. float resolution = 1.0f; if (PresShell* presShell =
APZCCallbackHelper::GetRootContentDocumentPresShellForContent(
aContent)) {
resolution = presShell->GetResolution();
}
// Now apply the callback-transform. This is only approximately correct, // see the comment on GetCumulativeApzCallbackTransform for details.
gfx::PointTyped<Units> transform;
CSSPoint transformCSS = nsLayoutUtils::GetCumulativeApzCallbackTransform(
aContent->GetPrimaryFrame()); if constexpr (std::is_same_v<Units, CSSPixel>) {
transform = transformCSS;
} else { // Units == LayoutDevicePixel
transform =
transformCSS *
aContent->GetPrimaryFrame()->PresContext()->CSSToDevPixelScale();
}
// In hit testing codepaths, the input rect often has dimensions of one app // units. If we are zoomed in enough, the rounded size of the output rect // can be zero app units, which will fail to Intersect() with anything, and // therefore cause hit testing to fail. To avoid this, we expand the output // rect to one app units. if (!aRect.IsEmpty() && result.IsEmpty()) {
result.width = 1;
result.height = 1;
}
// Walk up to the rootmost prescontext, transforming as we go. for (nsPresContext* ctx = aCtx; ctx; ctx = ctx->GetParentPresContext()) {
PresShell* shell = ctx->PresShell();
nsIFrame* rootFrame = shell->GetRootFrame(); if (prevRootFrame) { // Convert layoutToVisual from being relative to `prevRootFrame` // to being relative to `rootFrame` (layout space).
nscoord apd = prevCtx->AppUnitsPerDevPixel();
nsPoint offset = prevRootFrame->GetOffsetToCrossDoc(rootFrame, apd);
layoutToVisual += LayoutDevicePoint::FromAppUnits(offset, apd);
} if (shell->GetResolution() != 1.0) { // Found the APZ zoom root, so do the layout -> visual conversion.
layoutToVisual =
ViewportUtils::DocumentRelativeLayoutToVisual(layoutToVisual, shell);
}
prevRootFrame = rootFrame;
prevCtx = ctx;
}
// If we're in a nested content process, the above traversal will not have // encountered the APZ zoom root. The translation part of the layout-to-visual // transform will be included in |rootScreenRect.TopLeft()|, added below // (that ultimately comes from nsIWidget::WidgetToScreenOffset(), which for an // OOP iframe's widget includes this translation), but the scale part needs to // be computed and added separately.
Scale2D enclosingResolution =
ViewportUtils::TryInferEnclosingResolution(prevCtx->GetPresShell()); if (enclosingResolution != Scale2D{1.0f, 1.0f}) {
layoutToVisual = TransformPointOrRect(
LayoutDeviceToLayoutDeviceMatrix4x4::Scaling(
enclosingResolution.xScale, enclosingResolution.yScale, 1.0f),
layoutToVisual);
}
// Then we do the conversion from the rootmost presContext's root frame (in // visual space) to screen space.
LayoutDeviceIntRect rootScreenRect =
LayoutDeviceIntRect::FromAppUnitsToNearest(
prevRootFrame->GetScreenRectInAppUnits(),
prevCtx->AppUnitsPerDevPixel());
// Definitions of the two explicit instantiations forward declared in the header // file. This causes code for these instantiations to be emitted into the object // file for ViewportUtils.cpp. template CSSToCSSMatrix4x4Flagged
ViewportUtils::GetVisualToLayoutTransform<CSSPixel>(nsIContent*); template LayoutDeviceToLayoutDeviceMatrix4x4Flagged
ViewportUtils::GetVisualToLayoutTransform<LayoutDevicePixel>(nsIContent*);
const nsIFrame* ViewportUtils::IsZoomedContentRoot(const nsIFrame* aFrame) { if (!aFrame) { return nullptr;
} if (aFrame->Type() == LayoutFrameType::Canvas ||
aFrame->Type() == LayoutFrameType::PageSequence) {
ScrollContainerFrame* sf = do_QueryFrame(aFrame->GetParent()); if (sf && sf->IsRootScrollFrameOfDocument() &&
aFrame->PresContext()->IsRootContentDocumentCrossProcess()) { return aFrame->GetParent();
}
} elseif (aFrame->StyleDisplay()->mPosition ==
StylePositionProperty::Fixed) { if (ViewportFrame* viewportFrame = do_QueryFrame(aFrame->GetParent())) { if (viewportFrame->PresContext()->IsRootContentDocumentCrossProcess()) { return viewportFrame->PresShell()->GetRootScrollContainerFrame();
}
}
} return nullptr;
}
Scale2D ViewportUtils::TryInferEnclosingResolution(PresShell* aShell) { if (!XRE_IsContentProcess()) { return {1.0f, 1.0f};
}
MOZ_ASSERT(aShell && aShell->GetPresContext());
MOZ_ASSERT(!aShell->GetPresContext()->GetParentPresContext(), "TryInferEnclosingResolution can only be called for a root pres " "shell within a process"); if (dom::BrowserChild* bc = dom::BrowserChild::GetFrom(aShell)) { if (!bc->IsTopLevel()) { // The enclosing resolution is not directly available in the BrowserChild. // The closest thing available is GetChildToParentConversionMatrix(), // which also includes any enclosing CSS transforms. // The behaviour implemented here will not provide an accurate answer // in the presence of CSS transforms, but it tries to do something // reasonable: // - If there are no enclosing CSS transforms, it will return the // resolution. // - If the enclosing transforms contain scales and translations only, // it will return the resolution times the CSS transform scale // (choosing the x-scale if they are different). // - Otherwise, it will return the resolution times a scale component // of the transform as returned by Matrix4x4Typed::Decompose(). // - If the enclosing transform is sufficiently complex that // Decompose() returns false, give up and return 1.0.
gfx::Point3DTyped<gfx::UnknownUnits> translation;
gfx::Quaternion rotation;
gfx::Point3DTyped<gfx::UnknownUnits> scale; if (bc->GetChildToParentConversionMatrix().Decompose(translation,
rotation, scale)) { return {scale.x, scale.y};
}
}
} return {1.0f, 1.0f};
}
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.