// APZC sends us this request when we need to update the display port on // the scrollable frame the apzc is managing. void APZController::RequestContentRepaint(const FrameMetrics& aFrameMetrics) { #ifdef DEBUG_CONTROLLER WinUtils::Log("APZController::RequestContentRepaint scrollid=%I64d", aFrameMetrics.GetScrollId()); #endif // This must be on the gecko thread since we access the dom MOZ_ASSERT(NS_IsMainThread()); #ifdef DEBUG_CONTROLLER WinUtils::Log("APZController: mScrollOffset: %f %f", aFrameMetrics.mScrollOffset.x, aFrameMetrics.mScrollOffset.y); #endif nsCOMPtr<nsIDocument> subDocument; nsCOMPtr<nsIContent> targetContent; if (!GetDOMTargets(aFrameMetrics.GetScrollId(), subDocument, targetContent)) { return; } // If we're dealing with a sub frame or content editable element, // call UpdateSubFrame. if (targetContent) { #ifdef DEBUG_CONTROLLER WinUtils::Log("APZController: detected subframe or content editable"); #endif FrameMetrics metrics = aFrameMetrics; mozilla::layers::APZCCallbackHelper::UpdateSubFrame(targetContent, metrics); return; } #ifdef DEBUG_CONTROLLER WinUtils::Log("APZController: detected tab"); #endif // We're dealing with a tab, call UpdateRootFrame. nsCOMPtr<nsIDOMWindowUtils> utils; nsCOMPtr<nsIDOMWindow> window = subDocument->GetDefaultView(); if (window) { utils = do_GetInterface(window); if (utils) { FrameMetrics metrics = aFrameMetrics; mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, metrics); #ifdef DEBUG_CONTROLLER WinUtils::Log("APZController: %I64d mDisplayPortMargins: %0.2f %0.2f %0.2f %0.2f", metrics.GetScrollId(), metrics.GetDisplayPortMargins().left, metrics.GetDisplayPortMargins().top, metrics.GetDisplayPortMargins().right, metrics.GetDisplayPortMargins().bottom); #endif } } }
static void SetDisplayPortMargins(nsIDOMWindowUtils* aUtils, nsIContent* aContent, FrameMetrics& aMetrics) { if (!aContent) { return; } nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent); if (!element) { return; } ScreenMargin margins = aMetrics.GetDisplayPortMargins(); aUtils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(0, 0, baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); }
void APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent, FrameMetrics& aMetrics) { // Precondition checks MOZ_ASSERT(aContent); MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { return; } nsCOMPtr<nsIDOMWindowUtils> utils = GetDOMWindowUtils(aContent); if (!utils) { return; } // We currently do not support zooming arbitrary subframes. They can only // be scrolled, so here we only have to set the scroll position and displayport. nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent); if (element) { if (scrollUpdated) { AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { RecenterDisplayPort(aMetrics); } gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled() ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) : gfx::IntSize(0, 0); LayerMargin margins = aMetrics.GetDisplayPortMargins(); utils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, alignment.width, alignment.height, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); } aMetrics.SetScrollOffset(actualScrollOffset); }
void AppendToString(std::stringstream& aStream, const FrameMetrics& m, const char* pfx, const char* sfx, bool detailed) { aStream << pfx; AppendToString(aStream, m.GetCompositionBounds(), "{ [cb="); AppendToString(aStream, m.GetScrollableRect(), "] [sr="); AppendToString(aStream, m.GetScrollOffset(), "] [s="); if (m.GetDoSmoothScroll()) { AppendToString(aStream, m.GetSmoothScrollOffset(), "] [ss="); } AppendToString(aStream, m.GetDisplayPort(), "] [dp="); AppendToString(aStream, m.GetCriticalDisplayPort(), "] [cdp="); AppendToString(aStream, m.GetBackgroundColor(), "] [color="); if (!detailed) { AppendToString(aStream, m.GetScrollId(), "] [scrollId="); if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) { AppendToString(aStream, m.GetScrollParentId(), "] [scrollParent="); } if (m.IsRootContent()) { aStream << "] [rcd"; } if (m.HasClipRect()) { AppendToString(aStream, m.ClipRect(), "] [clip="); } AppendToString(aStream, m.GetZoom(), "] [z=", "] }"); } else { AppendToString(aStream, m.GetDisplayPortMargins(), " [dpm="); aStream << nsPrintfCString("] um=%d", m.GetUseDisplayPortMargins()).get(); AppendToString(aStream, m.GetRootCompositionSize(), "] [rcs="); AppendToString(aStream, m.GetViewport(), "] [v="); aStream << nsPrintfCString("] [z=(ld=%.3f r=%.3f", m.GetDevPixelsPerCSSPixel().scale, m.GetPresShellResolution()).get(); AppendToString(aStream, m.GetCumulativeResolution(), " cr="); AppendToString(aStream, m.GetZoom(), " z="); AppendToString(aStream, m.GetExtraResolution(), " er="); aStream << nsPrintfCString(")] [u=(%d %d %lu)", m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(), m.GetScrollGeneration()).get(); AppendToString(aStream, m.GetScrollParentId(), "] [p="); aStream << nsPrintfCString("] [i=(%ld %lld %d)] }", m.GetPresShellId(), m.GetScrollId(), m.IsRootContent()).get(); } aStream << sfx; }
static void SetDisplayPortMargins(nsIPresShell* aPresShell, nsIContent* aContent, const FrameMetrics& aMetrics) { if (!aContent) { return; } ScreenMargin margins = aMetrics.GetDisplayPortMargins(); nsLayoutUtils::SetDisplayPortMargins(aContent, aPresShell, margins, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(0, 0, baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); }
void AppendToString(std::stringstream& aStream, const FrameMetrics& m, const char* pfx, const char* sfx, bool detailed) { aStream << pfx; AppendToString(aStream, m.mCompositionBounds, "{ cb="); AppendToString(aStream, m.mScrollableRect, " sr="); AppendToString(aStream, m.GetScrollOffset(), " s="); if (m.GetDoSmoothScroll()) { AppendToString(aStream, m.GetSmoothScrollOffset(), " ss="); } AppendToString(aStream, m.mDisplayPort, " dp="); AppendToString(aStream, m.mCriticalDisplayPort, " cdp="); AppendToString(aStream, m.GetBackgroundColor(), " color="); if (!detailed) { AppendToString(aStream, m.GetScrollId(), " scrollId="); if (m.GetScrollParentId() != FrameMetrics::NULL_SCROLL_ID) { AppendToString(aStream, m.GetScrollParentId(), " scrollParent="); } aStream << nsPrintfCString(" z=%.3f }", m.GetZoom().scale).get(); } else { AppendToString(aStream, m.GetDisplayPortMargins(), " dpm="); aStream << nsPrintfCString(" um=%d", m.GetUseDisplayPortMargins()).get(); AppendToString(aStream, m.GetRootCompositionSize(), " rcs="); AppendToString(aStream, m.GetViewport(), " v="); aStream << nsPrintfCString(" z=(ld=%.3f r=%.3f cr=%.3f z=%.3f er=%.3f)", m.mDevPixelsPerCSSPixel.scale, m.mPresShellResolution, m.mCumulativeResolution.scale, m.GetZoom().scale, m.GetExtraResolution().scale).get(); aStream << nsPrintfCString(" u=(%d %d %lu)", m.GetScrollOffsetUpdated(), m.GetDoSmoothScroll(), m.GetScrollGeneration()).get(); AppendToString(aStream, m.GetScrollParentId(), " p="); aStream << nsPrintfCString(" i=(%ld %lld) }", m.GetPresShellId(), m.GetScrollId()).get(); } aStream << sfx; }
static void SetDisplayPortMargins(nsIPresShell* aPresShell, nsIContent* aContent, const FrameMetrics& aMetrics) { if (!aContent) { return; } bool hadDisplayPort = nsLayoutUtils::HasDisplayPort(aContent); ScreenMargin margins = aMetrics.GetDisplayPortMargins(); nsLayoutUtils::SetDisplayPortMargins(aContent, aPresShell, margins, 0); if (!hadDisplayPort) { nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors( aContent->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::Repaint); } CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(0, 0, baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); }
void APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils, FrameMetrics& aMetrics) { // Precondition checks MOZ_ASSERT(aUtils); MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { return; } // Set the scroll port size, which determines the scroll range. For example if // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent // overscroll). Note that if the content here was zoomed to 2x, the document would // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum // scroll range would be 900. Therefore this calculation depends on the zoom applied // to the content relative to the container. CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height); // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); if (scrollUpdated) { // Correct the display port due to the difference between mScrollOffset and the // actual scroll offset. AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { // For whatever reason we couldn't update the scroll offset on the scroll frame, // which means the data APZ used for its displayport calculation is stale. Fall // back to a sane default behaviour. Note that we don't tile-align the recentered // displayport because tile-alignment depends on the scroll position, and the // scroll position here is out of our control. See bug 966507 comment 21 for a // more detailed explanation. RecenterDisplayPort(aMetrics); } aMetrics.SetScrollOffset(actualScrollOffset); // The mZoom variable on the frame metrics stores the CSS-to-screen scale for this // frame. This scale includes all of the (cumulative) resolutions set on the presShells // from the root down to this frame. However, when setting the resolution, we only // want the piece of the resolution that corresponds to this presShell, rather than // all of the cumulative stuff, so we need to divide out the parent resolutions. // Finally, we multiply by a ScreenToLayerScale of 1.0f because the goal here is to // take the async zoom calculated by the APZC and tell gecko about it (turning it into // a "sync" zoom) which will update the resolution at which the layer is painted. ParentLayerToLayerScale presShellResolution = aMetrics.GetZoom() / aMetrics.mDevPixelsPerCSSPixel / aMetrics.GetParentResolution() * ScreenToLayerScale(1.0f); aUtils->SetResolution(presShellResolution.scale, presShellResolution.scale); // Finally, we set the displayport. nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId()); if (!content) { return; } nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content); if (!element) { return; } gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled() ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) : gfx::IntSize(0, 0); LayerMargin margins = aMetrics.GetDisplayPortMargins(); aUtils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, alignment.width, alignment.height, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base); }
void APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils, FrameMetrics& aMetrics) { // Precondition checks MOZ_ASSERT(aUtils); MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins()); if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { return; } // Set the scroll port size, which determines the scroll range. For example if // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent // overscroll). Note that if the content here was zoomed to 2x, the document would // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum // scroll range would be 900. Therefore this calculation depends on the zoom applied // to the content relative to the container. CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height); // Scroll the window to the desired spot nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); bool scrollUpdated = false; CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); if (scrollUpdated) { // Correct the display port due to the difference between mScrollOffset and the // actual scroll offset. AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset); } else { // For whatever reason we couldn't update the scroll offset on the scroll frame, // which means the data APZ used for its displayport calculation is stale. Fall // back to a sane default behaviour. Note that we don't tile-align the recentered // displayport because tile-alignment depends on the scroll position, and the // scroll position here is out of our control. See bug 966507 comment 21 for a // more detailed explanation. RecenterDisplayPort(aMetrics); } aMetrics.SetScrollOffset(actualScrollOffset); // The pres shell resolution is updated by the the async zoom since the // last paint. float presShellResolution = aMetrics.GetPresShellResolution() * aMetrics.GetAsyncZoom().scale; aUtils->SetResolutionAndScaleTo(presShellResolution, presShellResolution); // Finally, we set the displayport. nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId()); if (!content) { return; } nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content); if (!element) { return; } ScreenMargin margins = aMetrics.GetDisplayPortMargins(); aUtils->SetDisplayPortMarginsForElement(margins.left, margins.top, margins.right, margins.bottom, element, 0); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(0, 0, baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base); }