Bug 1631568 - Have nsLayoutUtils::GetFrameForPoint() and GetFramesForArea() take a RelativeTo parameter. r=tnikkel

This removes the need for FrameForPointOptions::IsRelativeToLayoutViewport,
and makes sure each call site of these functions indicates whether the
input point/rect is in visual or layout coordinates.

Several call sites were passing in layout coordinates without setting the
IsRelativeToLayoutViewport flag, which this patch corrects.

Differential Revision: https://phabricator.services.mozilla.com/D71705
This commit is contained in:
Botond Ballo 2020-05-05 15:24:12 +00:00
Родитель 37c373d1e9
Коммит 5cffd06241
17 изменённых файлов: 62 добавлений и 79 удалений

Просмотреть файл

@ -99,7 +99,7 @@ void DocAccessibleWrap::CacheViewportCallback(nsITimer* aTimer,
nsRect scrollPort = sf ? sf->GetScrollPortRect() : rootFrame->GetRect();
nsLayoutUtils::GetFramesForArea(
presShell->GetRootFrame(), scrollPort, frames,
RelativeTo{presShell->GetRootFrame()}, scrollPort, frames,
nsLayoutUtils::FrameForPointOption::OnlyVisible);
AccessibleHashtable inViewAccs;
for (size_t i = 0; i < frames.Length(); i++) {

Просмотреть файл

@ -527,16 +527,8 @@ Accessible* Accessible::ChildAtPoint(int32_t aX, int32_t aY,
nsPoint offset(presContext->DevPixelsToAppUnits(aX) - screenRect.X(),
presContext->DevPixelsToAppUnits(aY) - screenRect.Y());
// We need to take into account a non-1 resolution set on the presshell.
// This happens in mobile platforms with async pinch zooming.
offset = offset.RemoveResolution(presContext->PresShell()->GetResolution());
// We need to translate with the offset of the edge of the visual
// viewport from top edge of the layout viewport.
offset += presContext->PresShell()->GetVisualViewportOffset() -
presContext->PresShell()->GetLayoutViewportOffset();
nsIFrame* foundFrame = nsLayoutUtils::GetFrameForPoint(startFrame, offset);
nsIFrame* foundFrame = nsLayoutUtils::GetFrameForPoint(
RelativeTo{startFrame, ViewportType::Visual}, offset);
nsIContent* content = nullptr;
if (!foundFrame || !(content = foundFrame->GetContent()))

Просмотреть файл

@ -12334,7 +12334,7 @@ already_AddRefed<nsDOMCaretPosition> Document::CaretPositionFromPoint(
}
nsIFrame* ptFrame = nsLayoutUtils::GetFrameForPoint(
rootFrame, pt,
RelativeTo{rootFrame}, pt,
{FrameForPointOption::IgnorePaintSuppression,
FrameForPointOption::IgnoreCrossDoc});
if (!ptFrame) {

Просмотреть файл

@ -363,7 +363,7 @@ template <typename NodeOrElement>
static void QueryNodesFromRect(DocumentOrShadowRoot& aRoot, const nsRect& aRect,
EnumSet<FrameForPointOption> aOptions,
FlushLayout aShouldFlushLayout,
Multiple aMultiple,
Multiple aMultiple, ViewportType aViewportType,
nsTArray<RefPtr<NodeOrElement>>& aNodes) {
static_assert(std::is_same<nsINode, NodeOrElement>::value ||
std::is_same<Element, NodeOrElement>::value,
@ -395,7 +395,8 @@ static void QueryNodesFromRect(DocumentOrShadowRoot& aRoot, const nsRect& aRect,
aOptions += FrameForPointOption::IgnoreCrossDoc;
AutoTArray<nsIFrame*, 8> frames;
nsLayoutUtils::GetFramesForArea(rootFrame, aRect, frames, aOptions);
nsLayoutUtils::GetFramesForArea({rootFrame, aViewportType}, aRect, frames,
aOptions);
for (nsIFrame* frame : frames) {
nsIContent* content = doc->GetContentInThisDocument(frame);
@ -439,7 +440,7 @@ template <typename NodeOrElement>
static void QueryNodesFromPoint(DocumentOrShadowRoot& aRoot, float aX, float aY,
EnumSet<FrameForPointOption> aOptions,
FlushLayout aShouldFlushLayout,
Multiple aMultiple,
Multiple aMultiple, ViewportType aViewportType,
nsTArray<RefPtr<NodeOrElement>>& aNodes) {
// As per the spec, we return null if either coord is negative.
if (!aOptions.contains(FrameForPointOption::IgnoreRootScrollFrame) &&
@ -451,52 +452,47 @@ static void QueryNodesFromPoint(DocumentOrShadowRoot& aRoot, float aX, float aY,
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
QueryNodesFromRect(aRoot, nsRect(pt, nsSize(1, 1)), aOptions,
aShouldFlushLayout, aMultiple, aNodes);
aShouldFlushLayout, aMultiple, aViewportType, aNodes);
}
} // namespace
Element* DocumentOrShadowRoot::ElementFromPoint(float aX, float aY) {
return ElementFromPointHelper(aX, aY, false, true, true);
return ElementFromPointHelper(aX, aY, false, true, ViewportType::Layout);
}
void DocumentOrShadowRoot::ElementsFromPoint(
float aX, float aY, nsTArray<RefPtr<Element>>& aElements) {
QueryNodesFromPoint(*this, aX, aY,
FrameForPointOption::IsRelativeToLayoutViewport,
FlushLayout::Yes, Multiple::Yes, aElements);
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
ViewportType::Layout, aElements);
}
void DocumentOrShadowRoot::NodesFromPoint(float aX, float aY,
nsTArray<RefPtr<nsINode>>& aNodes) {
QueryNodesFromPoint(*this, aX, aY,
FrameForPointOption::IsRelativeToLayoutViewport,
FlushLayout::Yes, Multiple::Yes, aNodes);
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
ViewportType::Layout, aNodes);
}
nsINode* DocumentOrShadowRoot::NodeFromPoint(float aX, float aY) {
AutoTArray<RefPtr<nsINode>, 1> nodes;
QueryNodesFromPoint(*this, aX, aY,
FrameForPointOption::IsRelativeToLayoutViewport,
FlushLayout::Yes, Multiple::No, nodes);
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::No,
ViewportType::Layout, nodes);
return nodes.SafeElementAt(0);
}
Element* DocumentOrShadowRoot::ElementFromPointHelper(
float aX, float aY, bool aIgnoreRootScrollFrame, bool aFlushLayout,
bool aIsRelativeToLayoutViewport) {
ViewportType aViewportType) {
EnumSet<FrameForPointOption> options;
if (aIgnoreRootScrollFrame) {
options += FrameForPointOption::IgnoreRootScrollFrame;
}
if (aIsRelativeToLayoutViewport) {
options += FrameForPointOption::IsRelativeToLayoutViewport;
}
auto flush = aFlushLayout ? FlushLayout::Yes : FlushLayout::No;
AutoTArray<RefPtr<Element>, 1> elements;
QueryNodesFromPoint(*this, aX, aY, options, flush, Multiple::No, elements);
QueryNodesFromPoint(*this, aX, aY, options, flush, Multiple::No,
aViewportType, elements);
return elements.SafeElementAt(0);
}
@ -528,7 +524,8 @@ void DocumentOrShadowRoot::NodesFromRect(float aX, float aY, float aTopSize,
}
auto flush = aFlushLayout ? FlushLayout::Yes : FlushLayout::No;
QueryNodesFromRect(*this, rect, options, flush, Multiple::Yes, aReturn);
QueryNodesFromRect(*this, rect, options, flush, Multiple::Yes,
ViewportType::Layout, aReturn);
}
Element* DocumentOrShadowRoot::AddIDTargetObserver(nsAtom* aID,

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/dom/NameSpaceConstants.h"
#include "mozilla/IdentifierMapEntry.h"
#include "mozilla/RelativeTo.h"
#include "nsClassHashtable.h"
#include "nsContentListDeclarations.h"
#include "nsTArray.h"
@ -136,7 +137,7 @@ class DocumentOrShadowRoot {
Element* ElementFromPointHelper(float aX, float aY,
bool aIgnoreRootScrollFrame,
bool aFlushLayout,
bool aIsRelativeToLayoutViewport);
ViewportType aViewportType);
void NodesFromRect(float aX, float aY, float aTopSize, float aRightSize,
float aBottomSize, float aLeftSize,

Просмотреть файл

@ -1156,7 +1156,7 @@ nsDOMWindowUtils::ElementFromPoint(float aX, float aY,
NS_ENSURE_STATE(doc);
RefPtr<Element> el = doc->ElementFromPointHelper(
aX, aY, aIgnoreRootScrollFrame, aFlushLayout, false);
aX, aY, aIgnoreRootScrollFrame, aFlushLayout, ViewportType::Layout);
el.forget(aReturn);
return NS_OK;
}
@ -3233,7 +3233,8 @@ nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior,
nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext());
nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
widget, pt, RelativeTo{rootFrame});
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
nsIFrame* targetFrame =
nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
// This can happen if the page hasn't loaded yet or if the point
// is outside the frame.
if (!targetFrame) {

Просмотреть файл

@ -2552,9 +2552,8 @@ nsresult ContentEventHandler::OnQueryCharacterAtPoint(
nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
&eventOnRoot, RelativeTo{rootFrame});
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(
rootFrame, ptInRoot,
{nsLayoutUtils::FrameForPointOption::IsRelativeToLayoutViewport});
nsIFrame* targetFrame =
nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
if (!targetFrame || !targetFrame->GetContent() ||
!targetFrame->GetContent()->IsInclusiveDescendantOf(mRootContent)) {
// There is no character at the point.
@ -2650,7 +2649,7 @@ nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
docFrameRect.y);
Element* contentUnderMouse = mDocument->ElementFromPointHelper(
eventLocCSS.x, eventLocCSS.y, false, false, false);
eventLocCSS.x, eventLocCSS.y, false, false, ViewportType::Visual);
if (contentUnderMouse) {
nsIWidget* targetWidget = nullptr;
nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame();

Просмотреть файл

@ -565,9 +565,10 @@ static bool PrepareForSetTargetAPZCNotification(
const LayoutDeviceIntPoint& aRefPoint,
nsTArray<ScrollableLayerGuid>* aTargets) {
ScrollableLayerGuid guid(aLayersId, 0, ScrollableLayerGuid::NULL_SCROLL_ID);
RelativeTo relativeTo{aRootFrame, ViewportType::Visual};
nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
aWidget, aRefPoint, RelativeTo{aRootFrame, ViewportType::Visual});
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, point);
aWidget, aRefPoint, relativeTo);
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(relativeTo, point);
nsIScrollableFrame* scrollAncestor =
target ? nsLayoutUtils::GetAsyncScrollableAncestorFrame(target)
: aRootFrame->PresShell()->GetRootScrollFrameAsScrollable();

Просмотреть файл

@ -27,13 +27,12 @@ namespace {
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
// Returns the DOM element found at |aPoint|, interpreted as being relative to
// the root frame of |aPresShell|. If the point is inside a subdocument, returns
// an element inside the subdocument, rather than the subdocument element
// (and does so recursively).
// The implementation was adapted from DocumentOrShadowRoot::ElementFromPoint(),
// with the notable exception that we don't pass nsLayoutUtils::IGNORE_CROSS_DOC
// to GetFrameForPoint(), so as to get the behaviour described above in the
// presence of subdocuments.
// the root frame of |aPresShell| in visual coordinates. If the point is inside
// a subdocument, returns an element inside the subdocument, rather than the
// subdocument element (and does so recursively). The implementation was adapted
// from DocumentOrShadowRoot::ElementFromPoint(), with the notable exception
// that we don't pass nsLayoutUtils::IGNORE_CROSS_DOC to GetFrameForPoint(), so
// as to get the behaviour described above in the presence of subdocuments.
static already_AddRefed<dom::Element> ElementFromPoint(
const RefPtr<PresShell>& aPresShell, const CSSPoint& aPoint) {
nsIFrame* rootFrame = aPresShell->GetRootFrame();
@ -41,7 +40,7 @@ static already_AddRefed<dom::Element> ElementFromPoint(
return nullptr;
}
nsIFrame* frame = nsLayoutUtils::GetFrameForPoint(
rootFrame, CSSPoint::ToAppUnits(aPoint),
RelativeTo{rootFrame, ViewportType::Visual}, CSSPoint::ToAppUnits(aPoint),
{FrameForPointOption::IgnorePaintSuppression});
while (frame && (!frame->GetContent() ||
frame->GetContent()->IsInAnonymousSubtree())) {

Просмотреть файл

@ -57,8 +57,7 @@ TouchBehaviorFlags TouchActionHelper::GetAllowedTouchBehavior(
nsPoint relativePoint =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, aRootFrame);
nsIFrame* target =
nsLayoutUtils::GetFrameForPoint(aRootFrame.mFrame, relativePoint);
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, relativePoint);
if (!target) {
return behavior;
}

Просмотреть файл

@ -544,8 +544,8 @@ nsresult AccessibleCaretManager::SelectWordOrShortcut(const nsPoint& aPoint) {
}
// Find the frame under point.
AutoWeakFrame ptFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, aPoint, GetHitTestOptions());
AutoWeakFrame ptFrame = nsLayoutUtils::GetFrameForPoint(
RelativeTo{rootFrame}, aPoint, GetHitTestOptions());
if (!ptFrame.GetFrame()) {
return NS_ERROR_FAILURE;
}
@ -1217,8 +1217,8 @@ nsresult AccessibleCaretManager::DragCaretInternal(const nsPoint& aPoint) {
// Find out which content we point to
nsIFrame* ptFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, point, GetHitTestOptions());
nsIFrame* ptFrame = nsLayoutUtils::GetFrameForPoint(
RelativeTo{rootFrame}, point, GetHitTestOptions());
if (!ptFrame) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -430,11 +430,8 @@ nsIFrame* FindFrameTargetedByInputEvent(
if (aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME) {
options += FrameForPointOption::IgnoreRootScrollFrame;
}
if (aRootFrame.mViewportType == ViewportType::Layout) {
options += FrameForPointOption::IsRelativeToLayoutViewport;
}
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(
aRootFrame.mFrame, aPointRelativeToRootFrame, options);
aRootFrame, aPointRelativeToRootFrame, options);
PET_LOG(
"Found initial target %p for event class %s message %s point %s "
"relative to root frame %p\n",
@ -482,7 +479,7 @@ nsIFrame* FindFrameTargetedByInputEvent(
PET_LOG("Expanded point to target rect %s\n",
mozilla::layers::Stringify(targetRect).c_str());
AutoTArray<nsIFrame*, 8> candidates;
nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame.mFrame, targetRect,
nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame, targetRect,
candidates, options);
if (NS_FAILED(rv)) {
return target;

Просмотреть файл

@ -3175,23 +3175,24 @@ struct AutoNestedPaintCount {
#endif
nsIFrame* nsLayoutUtils::GetFrameForPoint(
const nsIFrame* aFrame, nsPoint aPt,
RelativeTo aRelativeTo, nsPoint aPt,
EnumSet<FrameForPointOption> aOptions) {
AUTO_PROFILER_LABEL("nsLayoutUtils::GetFrameForPoint", LAYOUT);
nsresult rv;
AutoTArray<nsIFrame*, 8> outFrames;
rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames, aOptions);
rv = GetFramesForArea(aRelativeTo, nsRect(aPt, nsSize(1, 1)), outFrames,
aOptions);
NS_ENSURE_SUCCESS(rv, nullptr);
return outFrames.Length() ? outFrames.ElementAt(0) : nullptr;
}
nsresult nsLayoutUtils::GetFramesForArea(
const nsIFrame* aFrame, const nsRect& aRect,
RelativeTo aRelativeTo, const nsRect& aRect,
nsTArray<nsIFrame*>& aOutFrames, EnumSet<FrameForPointOption> aOptions) {
AUTO_PROFILER_LABEL("nsLayoutUtils::GetFramesForArea", LAYOUT);
nsIFrame* frame = const_cast<nsIFrame*>(aFrame);
nsIFrame* frame = const_cast<nsIFrame*>(aRelativeTo.mFrame);
nsDisplayListBuilder builder(frame, nsDisplayListBuilderMode::EventDelivery,
false);
@ -3202,12 +3203,12 @@ nsresult nsLayoutUtils::GetFramesForArea(
builder.IgnorePaintSuppression();
}
if (aOptions.contains(FrameForPointOption::IgnoreRootScrollFrame)) {
nsIFrame* rootScrollFrame = aFrame->PresShell()->GetRootScrollFrame();
nsIFrame* rootScrollFrame = frame->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
builder.SetIgnoreScrollFrame(rootScrollFrame);
}
}
if (aOptions.contains(FrameForPointOption::IsRelativeToLayoutViewport)) {
if (aRelativeTo.mViewportType == ViewportType::Layout) {
builder.SetIsRelativeToLayoutViewport();
}
if (aOptions.contains(FrameForPointOption::IgnoreCrossDoc)) {

Просмотреть файл

@ -882,33 +882,29 @@ class nsLayoutUtils {
* When set, return only content that is actually visible.
*/
OnlyVisible,
/**
* When set, coordinates are interpreted as being relative to the layout
* viewport. When not set, coordinates are interpreted as being relative
* to the visual viewport.
*/
IsRelativeToLayoutViewport,
};
/**
* Given aFrame, the root frame of a stacking context, find its descendant
* frame under the point aPt that receives a mouse event at that location,
* or nullptr if there is no such frame.
* @param aPt the point, relative to the frame origin
* @param aPt the point, relative to the frame origin, in either visual
* or layout coordinates depending on aRelativeTo.mViewportType
* @param aFlags some combination of FrameForPointOption.
*/
static nsIFrame* GetFrameForPoint(const nsIFrame* aFrame, nsPoint aPt,
static nsIFrame* GetFrameForPoint(RelativeTo aRelativeTo, nsPoint aPt,
mozilla::EnumSet<FrameForPointOption> = {});
/**
* Given aFrame, the root frame of a stacking context, find all descendant
* frames under the area of a rectangle that receives a mouse event,
* or nullptr if there is no such frame.
* @param aRect the rect, relative to the frame origin
* @param aRect the rect, relative to the frame origin, in either visual
* or layout coordinates depending on aRelativeTo.mViewportType
* @param aOutFrames an array to add all the frames found
* @param aFlags some combination of FrameForPointOption.
*/
static nsresult GetFramesForArea(const nsIFrame* aFrame, const nsRect& aRect,
static nsresult GetFramesForArea(RelativeTo aRelativeTo, const nsRect& aRect,
nsTArray<nsIFrame*>& aOutFrames,
mozilla::EnumSet<FrameForPointOption> = {});

Просмотреть файл

@ -531,7 +531,7 @@ nsresult nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(
nsIFrame* rootFrame = mPresShell->GetRootFrame();
nsPoint ptInRoot = aPoint + aFrame->GetOffsetTo(rootFrame);
nsIFrame* cursorFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
// If the mouse cursor in on a frame which is descendant of same
// selection root, we can expand the selection to the frame.

Просмотреть файл

@ -308,7 +308,7 @@ nsIFrame* nsSVGForeignObjectFrame::GetFrameForPoint(const gfxPoint& aPoint) {
gfxPoint pt = (aPoint + gfxPoint(x, y)) * AppUnitsPerCSSPixel();
nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
return nsLayoutUtils::GetFrameForPoint(kid, point);
return nsLayoutUtils::GetFrameForPoint(RelativeTo{kid}, point);
}
void nsSVGForeignObjectFrame::ReflowSVG() {

Просмотреть файл

@ -1186,7 +1186,7 @@ bool nsTypeAheadFind::IsRangeRendered(nsRange* aRange) {
nsPresContext::CSSPixelsToAppUnits((float)rect->Height()));
// Append visible frames to frames array.
nsLayoutUtils::GetFramesForArea(
rootFrame, r, frames,
RelativeTo{rootFrame}, r, frames,
{FrameForPointOption::IgnorePaintSuppression,
FrameForPointOption::IgnoreRootScrollFrame,
FrameForPointOption::OnlyVisible});