From f34c3edf90cc60fe2ad3e5b60553d24a0b6c8a05 Mon Sep 17 00:00:00 2001 From: James Teh Date: Wed, 31 May 2023 10:04:18 +0000 Subject: [PATCH] Bug 1828295 part 1: Fix HyperTextAccessible::GetCaretRect when the title bar is enabled. r=morgan I don't quite know which part of this was breaking, but the coordinates were quite wrong in the parent process. They were wrong enough that when we adjusted for the character height, we ended up with a negative height in the resulting rect. This code is now more similar to how we do this in LocalAccessible::BoundsInAppUnits. This should also take CSS transforms into account in most cases where we weren't previously, though perhaps not for some iframe transforms. Differential Revision: https://phabricator.services.mozilla.com/D176619 --- accessible/generic/HyperTextAccessible.cpp | 36 +++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp index dc9ad8609dbb..943ac63c1c94 100644 --- a/accessible/generic/HyperTextAccessible.cpp +++ b/accessible/generic/HyperTextAccessible.cpp @@ -33,6 +33,7 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIScrollableFrame.h" #include "nsIMathMLFrame.h" +#include "nsLayoutUtils.h" #include "nsRange.h" #include "nsTextFragment.h" #include "mozilla/Assertions.h" @@ -731,20 +732,25 @@ LayoutDeviceIntRect HyperTextAccessible::GetCaretRect(nsIWidget** aWidget) { nsIFrame* frame = caret->GetGeometry(&rect); if (!frame || rect.IsEmpty()) return LayoutDeviceIntRect(); - nsPoint offset; - // Offset from widget origin to the frame origin, which includes chrome - // on the widget. - *aWidget = frame->GetNearestWidget(offset); - NS_ENSURE_TRUE(*aWidget, LayoutDeviceIntRect()); - rect.MoveBy(offset); - - LayoutDeviceIntRect caretRect = LayoutDeviceIntRect::FromUnknownRect( - rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel())); - // clang-format off - // ((content screen origin) - (content offset in the widget)) = widget origin on the screen - // clang-format on - caretRect.MoveBy((*aWidget)->WidgetToScreenOffset() - - (*aWidget)->GetClientOffset()); + PresShell* presShell = mDoc->PresShellPtr(); + // Transform rect to be relative to the root frame. + nsIFrame* rootFrame = presShell->GetRootFrame(); + rect = nsLayoutUtils::TransformFrameRectToAncestor(frame, rect, rootFrame); + // We need to inverse translate with the offset of the edge of the visual + // viewport from top edge of the layout viewport. + nsPoint viewportOffset = presShell->GetVisualViewportOffset() - + presShell->GetLayoutViewportOffset(); + rect.MoveBy(-viewportOffset); + // We need to take into account a non-1 resolution set on the presshell. + // This happens with async pinch zooming. Here we scale the bounds before + // adding the screen-relative offset. + rect.ScaleRoundOut(presShell->GetResolution()); + // Now we need to put the rect in absolute screen coords. + nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits(); + rect.MoveBy(rootScreenRect.TopLeft()); + // Finally, convert from app units. + auto caretRect = LayoutDeviceIntRect::FromAppUnitsToNearest( + rect, presShell->GetPresContext()->AppUnitsPerDevPixel()); // Correct for character size, so that caret always matches the size of // the character. This is important for font size transitions, and is @@ -763,6 +769,8 @@ LayoutDeviceIntRect HyperTextAccessible::GetCaretRect(nsIWidget** aWidget) { if (!charRect.IsEmpty()) { caretRect.SetTopEdge(charRect.Y()); } + + *aWidget = frame->GetNearestWidget(); return caretRect; }