mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-13 06:38:48 +02:00
Bug 918288 - Ensure we set a displayport on elements that we get touch-start events for. r=botond
This commit is contained in:
parent
911702f6c3
commit
0611166ee2
3 changed files with 119 additions and 34 deletions
|
|
@ -2395,24 +2395,27 @@ TabChild::CancelTapTracking()
|
||||||
mTapHoldTimer = nullptr;
|
mTapHoldTimer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dom::Element*
|
static nsIScrollableFrame*
|
||||||
GetScrollableAncestor(nsIFrame* aTarget)
|
GetScrollableAncestorFrame(nsIFrame* aTarget)
|
||||||
{
|
{
|
||||||
if (!aTarget) {
|
if (!aTarget) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT
|
uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT
|
||||||
| nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE;
|
| nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE;
|
||||||
nsIScrollableFrame* scrollTarget = nsLayoutUtils::GetNearestScrollableFrame(
|
return nsLayoutUtils::GetNearestScrollableFrame(aTarget, flags);
|
||||||
aTarget, flags);
|
}
|
||||||
if (!scrollTarget) {
|
|
||||||
|
static dom::Element*
|
||||||
|
GetDisplayportElementFor(nsIScrollableFrame* aScrollableFrame)
|
||||||
|
{
|
||||||
|
if (!aScrollableFrame) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
nsIFrame* scrolledFrame = scrollTarget->GetScrolledFrame();
|
nsIFrame* scrolledFrame = aScrollableFrame->GetScrolledFrame();
|
||||||
if (!scrolledFrame) {
|
if (!scrolledFrame) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// |scrolledFrame| should at this point be the root content frame of the
|
// |scrolledFrame| should at this point be the root content frame of the
|
||||||
// nearest ancestor scrollable frame. The element corresponding to this
|
// nearest ancestor scrollable frame. The element corresponding to this
|
||||||
// frame should be the one with the displayport set on it, so find that
|
// frame should be the one with the displayport set on it, so find that
|
||||||
|
|
@ -2422,6 +2425,49 @@ GetScrollableAncestor(nsIFrame* aTarget)
|
||||||
return content->AsElement();
|
return content->AsElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DisplayportSetListener : public nsAPostRefreshObserver {
|
||||||
|
public:
|
||||||
|
DisplayportSetListener(TabChild* aTabChild,
|
||||||
|
nsIPresShell* aPresShell,
|
||||||
|
const uint64_t& aInputBlockId,
|
||||||
|
const nsTArray<ScrollableLayerGuid>& aTargets)
|
||||||
|
: mTabChild(aTabChild)
|
||||||
|
, mPresShell(aPresShell)
|
||||||
|
, mInputBlockId(aInputBlockId)
|
||||||
|
, mTargets(aTargets)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~DisplayportSetListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DidRefresh() MOZ_OVERRIDE {
|
||||||
|
if (!mTabChild) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Post-refresh observer fired again after failed attempt at unregistering it");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTabChild->SendSetTargetAPZC(mInputBlockId, mTargets);
|
||||||
|
|
||||||
|
if (!mPresShell->RemovePostRefreshObserver(this)) {
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Unable to unregister post-refresh observer! Leaking it instead of leaving garbage registered");
|
||||||
|
// Graceful handling, just in case...
|
||||||
|
mTabChild = nullptr;
|
||||||
|
mPresShell = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<TabChild> mTabChild;
|
||||||
|
nsRefPtr<nsIPresShell> mPresShell;
|
||||||
|
uint64_t mInputBlockId;
|
||||||
|
nsTArray<ScrollableLayerGuid> mTargets;
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
||||||
const ScrollableLayerGuid& aGuid,
|
const ScrollableLayerGuid& aGuid,
|
||||||
|
|
@ -2437,6 +2483,7 @@ TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool waitForRefresh = false;
|
||||||
nsTArray<ScrollableLayerGuid> targets;
|
nsTArray<ScrollableLayerGuid> targets;
|
||||||
for (size_t i = 0; i < aEvent.touches.Length(); i++) {
|
for (size_t i = 0; i < aEvent.touches.Length(); i++) {
|
||||||
ScrollableLayerGuid guid(aGuid.mLayersId, 0, FrameMetrics::NULL_SCROLL_ID);
|
ScrollableLayerGuid guid(aGuid.mLayersId, 0, FrameMetrics::NULL_SCROLL_ID);
|
||||||
|
|
@ -2444,13 +2491,25 @@ TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
||||||
WebWidget(), aEvent.touches[i]->mRefPoint, rootFrame);
|
WebWidget(), aEvent.touches[i]->mRefPoint, rootFrame);
|
||||||
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(rootFrame, touchPoint,
|
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(rootFrame, touchPoint,
|
||||||
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
|
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
|
||||||
APZCCallbackHelper::GetOrCreateScrollIdentifiers(
|
nsIScrollableFrame* scrollAncestor = GetScrollableAncestorFrame(target);
|
||||||
GetScrollableAncestor(target),
|
nsCOMPtr<dom::Element> dpElement = GetDisplayportElementFor(scrollAncestor);
|
||||||
&(guid.mPresShellId),
|
|
||||||
&(guid.mScrollId));
|
bool guidIsValid = APZCCallbackHelper::GetOrCreateScrollIdentifiers(
|
||||||
|
dpElement, &(guid.mPresShellId), &(guid.mScrollId));
|
||||||
targets.AppendElement(guid);
|
targets.AppendElement(guid);
|
||||||
|
|
||||||
|
if (guidIsValid && !nsLayoutUtils::GetDisplayPort(dpElement, nullptr)) {
|
||||||
|
waitForRefresh |= nsLayoutUtils::CalculateAndSetDisplayPortMargins(
|
||||||
|
scrollAncestor, nsLayoutUtils::RepaintMode::Repaint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (waitForRefresh) {
|
||||||
|
waitForRefresh = shell->AddPostRefreshObserver(
|
||||||
|
new DisplayportSetListener(this, shell, aInputBlockId, targets));
|
||||||
|
}
|
||||||
|
if (!waitForRefresh) {
|
||||||
|
SendSetTargetAPZC(aInputBlockId, targets);
|
||||||
}
|
}
|
||||||
SendSetTargetAPZC(aInputBlockId, targets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -988,7 +988,7 @@ nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
|
||||||
return GetDisplayPortImpl(aContent, aResult, 1.0f);
|
return GetDisplayPortImpl(aContent, aResult, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
||||||
nsIPresShell* aPresShell,
|
nsIPresShell* aPresShell,
|
||||||
const ScreenMargin& aMargins,
|
const ScreenMargin& aMargins,
|
||||||
|
|
@ -998,7 +998,7 @@ nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
||||||
DisplayPortMarginsPropertyData* currentData =
|
DisplayPortMarginsPropertyData* currentData =
|
||||||
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
|
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
|
||||||
if (currentData && currentData->mPriority > aPriority) {
|
if (currentData && currentData->mPriority > aPriority) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
|
aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
|
||||||
|
|
@ -1022,6 +1022,8 @@ nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
||||||
rootFrame->SchedulePaint();
|
rootFrame->SchedulePaint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2737,20 +2739,22 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// aScrollFrame and aScrollFrameAsScrollable must be non-nullptr
|
// aScrollFrameAsScrollable must be non-nullptr and queryable to an nsIFrame
|
||||||
static FrameMetrics
|
static FrameMetrics
|
||||||
CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
CalculateFrameMetricsForDisplayPort(nsIScrollableFrame* aScrollFrame) {
|
||||||
nsIScrollableFrame* aScrollFrameAsScrollable) {
|
nsIFrame* frame = do_QueryFrame(aScrollFrame);
|
||||||
|
MOZ_ASSERT(frame);
|
||||||
|
|
||||||
// Calculate the metrics necessary for calculating the displayport.
|
// Calculate the metrics necessary for calculating the displayport.
|
||||||
// This code has a lot in common with the code in ComputeFrameMetrics();
|
// This code has a lot in common with the code in ComputeFrameMetrics();
|
||||||
// we may want to refactor this at some point.
|
// we may want to refactor this at some point.
|
||||||
FrameMetrics metrics;
|
FrameMetrics metrics;
|
||||||
nsPresContext* presContext = aScrollFrame->PresContext();
|
nsPresContext* presContext = frame->PresContext();
|
||||||
nsIPresShell* presShell = presContext->PresShell();
|
nsIPresShell* presShell = presContext->PresShell();
|
||||||
CSSToLayoutDeviceScale deviceScale(float(nsPresContext::AppUnitsPerCSSPixel())
|
CSSToLayoutDeviceScale deviceScale(float(nsPresContext::AppUnitsPerCSSPixel())
|
||||||
/ presContext->AppUnitsPerDevPixel());
|
/ presContext->AppUnitsPerDevPixel());
|
||||||
float resolution = 1.0f;
|
float resolution = 1.0f;
|
||||||
if (aScrollFrame == presShell->GetRootScrollFrame()) {
|
if (frame == presShell->GetRootScrollFrame()) {
|
||||||
// Only the root scrollable frame for a given presShell should pick up
|
// Only the root scrollable frame for a given presShell should pick up
|
||||||
// the presShell's resolution. All the other frames are 1.0.
|
// the presShell's resolution. All the other frames are 1.0.
|
||||||
resolution = presShell->GetXResolution();
|
resolution = presShell->GetXResolution();
|
||||||
|
|
@ -2763,7 +2767,7 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
||||||
// and leaving mExtraResolution at 1.
|
// and leaving mExtraResolution at 1.
|
||||||
LayoutDeviceToLayerScale cumulativeResolution(
|
LayoutDeviceToLayerScale cumulativeResolution(
|
||||||
presShell->GetCumulativeResolution().width
|
presShell->GetCumulativeResolution().width
|
||||||
* nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame).width);
|
* nsLayoutUtils::GetTransformToAncestorScale(frame).width);
|
||||||
|
|
||||||
LayerToParentLayerScale layerToParentLayerScale(1.0f);
|
LayerToParentLayerScale layerToParentLayerScale(1.0f);
|
||||||
metrics.mDevPixelsPerCSSPixel = deviceScale;
|
metrics.mDevPixelsPerCSSPixel = deviceScale;
|
||||||
|
|
@ -2773,9 +2777,9 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
||||||
|
|
||||||
// Only the size of the composition bounds is relevant to the
|
// Only the size of the composition bounds is relevant to the
|
||||||
// displayport calculation, not its origin.
|
// displayport calculation, not its origin.
|
||||||
nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(aScrollFrame);
|
nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(frame);
|
||||||
LayoutDeviceToParentLayerScale compBoundsScale(1.0f);
|
LayoutDeviceToParentLayerScale compBoundsScale(1.0f);
|
||||||
if (aScrollFrame == presShell->GetRootScrollFrame() && presContext->IsRootContentDocument()) {
|
if (frame == presShell->GetRootScrollFrame() && presContext->IsRootContentDocument()) {
|
||||||
if (presContext->GetParentPresContext()) {
|
if (presContext->GetParentPresContext()) {
|
||||||
gfxSize res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
|
gfxSize res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
|
||||||
compBoundsScale = LayoutDeviceToParentLayerScale(res.width, res.height);
|
compBoundsScale = LayoutDeviceToParentLayerScale(res.width, res.height);
|
||||||
|
|
@ -2789,17 +2793,33 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
||||||
* compBoundsScale;
|
* compBoundsScale;
|
||||||
|
|
||||||
metrics.SetRootCompositionSize(
|
metrics.SetRootCompositionSize(
|
||||||
nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame, false, metrics));
|
nsLayoutUtils::CalculateRootCompositionSize(frame, false, metrics));
|
||||||
|
|
||||||
metrics.SetScrollOffset(CSSPoint::FromAppUnits(
|
metrics.SetScrollOffset(CSSPoint::FromAppUnits(
|
||||||
aScrollFrameAsScrollable->GetScrollPosition()));
|
aScrollFrame->GetScrollPosition()));
|
||||||
|
|
||||||
metrics.mScrollableRect = CSSRect::FromAppUnits(
|
metrics.mScrollableRect = CSSRect::FromAppUnits(
|
||||||
nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrameAsScrollable, nullptr));
|
nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrame, nullptr));
|
||||||
|
|
||||||
return metrics;
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsLayoutUtils::CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFrame,
|
||||||
|
RepaintMode aRepaintMode) {
|
||||||
|
nsIFrame* frame = do_QueryFrame(aScrollFrame);
|
||||||
|
MOZ_ASSERT(frame);
|
||||||
|
nsIContent* content = frame->GetContent();
|
||||||
|
MOZ_ASSERT(content);
|
||||||
|
|
||||||
|
FrameMetrics metrics = CalculateFrameMetricsForDisplayPort(aScrollFrame);
|
||||||
|
ScreenMargin displayportMargins = APZCTreeManager::CalculatePendingDisplayPort(
|
||||||
|
metrics, ParentLayerPoint(0.0f, 0.0f), 0.0);
|
||||||
|
nsIPresShell* presShell = frame->PresContext()->GetPresShell();
|
||||||
|
return nsLayoutUtils::SetDisplayPortMargins(
|
||||||
|
content, presShell, displayportMargins, 0, aRepaintMode);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
||||||
nsIFrame* aScrollFrame,
|
nsIFrame* aScrollFrame,
|
||||||
|
|
@ -2830,13 +2850,7 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
||||||
|
|
||||||
// If we don't already have a displayport, calculate and set one.
|
// If we don't already have a displayport, calculate and set one.
|
||||||
if (!haveDisplayPort) {
|
if (!haveDisplayPort) {
|
||||||
FrameMetrics metrics = CalculateFrameMetricsForDisplayPort(aScrollFrame, scrollableFrame);
|
CalculateAndSetDisplayPortMargins(scrollableFrame, nsLayoutUtils::RepaintMode::DoNotRepaint);
|
||||||
ScreenMargin displayportMargins = APZCTreeManager::CalculatePendingDisplayPort(
|
|
||||||
metrics, ParentLayerPoint(0.0f, 0.0f), 0.0);
|
|
||||||
nsIPresShell* presShell = aScrollFrame->PresContext()->GetPresShell();
|
|
||||||
nsLayoutUtils::SetDisplayPortMargins(
|
|
||||||
content, presShell, displayportMargins,
|
|
||||||
0, nsLayoutUtils::RepaintMode::DoNotRepaint);
|
|
||||||
haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
|
haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
|
||||||
NS_ASSERTION(haveDisplayPort, "should have a displayport after having just set it");
|
NS_ASSERTION(haveDisplayPort, "should have a displayport after having just set it");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,9 @@ public:
|
||||||
* @param aPriority a priority value to determine which margins take effect
|
* @param aPriority a priority value to determine which margins take effect
|
||||||
* when multiple callers specify margins
|
* when multiple callers specify margins
|
||||||
* @param aRepaintMode whether to schedule a paint after setting the margins
|
* @param aRepaintMode whether to schedule a paint after setting the margins
|
||||||
|
* @return true if the new margins were applied.
|
||||||
*/
|
*/
|
||||||
static void SetDisplayPortMargins(nsIContent* aContent,
|
static bool SetDisplayPortMargins(nsIContent* aContent,
|
||||||
nsIPresShell* aPresShell,
|
nsIPresShell* aPresShell,
|
||||||
const ScreenMargin& aMargins,
|
const ScreenMargin& aMargins,
|
||||||
uint32_t aPriority = 0,
|
uint32_t aPriority = 0,
|
||||||
|
|
@ -2429,7 +2430,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Calculate a default set of displayport margins for the given scrollframe
|
||||||
|
* and set them on the scrollframe's content element. The margins are set with
|
||||||
|
* the default priority, which may clobber previously set margins. The repaint
|
||||||
|
* mode provided is passed through to the call to SetDisplayPortMargins.
|
||||||
|
* The |aScrollFrame| parameter must be non-null and queryable to an nsIFrame.
|
||||||
|
* @return true iff the call to SetDisplayPortMargins returned true.
|
||||||
|
*/
|
||||||
|
static bool CalculateAndSetDisplayPortMargins(nsIScrollableFrame* aScrollFrame,
|
||||||
|
RepaintMode aRepaintMode);
|
||||||
|
|
||||||
|
/**
|
||||||
* Get the display port for |aScrollFrame|'s content. If |aScrollFrame|
|
* Get the display port for |aScrollFrame|'s content. If |aScrollFrame|
|
||||||
* WantsAsyncScroll() and we don't have a scrollable displayport yet (as
|
* WantsAsyncScroll() and we don't have a scrollable displayport yet (as
|
||||||
* tracked by |aBuilder|), calculate and set a display port. Returns true if
|
* tracked by |aBuilder|), calculate and set a display port. Returns true if
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue