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; }
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; }
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; }