mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-12 14:20:14 +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;
|
||||
}
|
||||
|
||||
static dom::Element*
|
||||
GetScrollableAncestor(nsIFrame* aTarget)
|
||||
static nsIScrollableFrame*
|
||||
GetScrollableAncestorFrame(nsIFrame* aTarget)
|
||||
{
|
||||
if (!aTarget) {
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT
|
||||
| nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE;
|
||||
nsIScrollableFrame* scrollTarget = nsLayoutUtils::GetNearestScrollableFrame(
|
||||
aTarget, flags);
|
||||
if (!scrollTarget) {
|
||||
return nsLayoutUtils::GetNearestScrollableFrame(aTarget, flags);
|
||||
}
|
||||
|
||||
static dom::Element*
|
||||
GetDisplayportElementFor(nsIScrollableFrame* aScrollableFrame)
|
||||
{
|
||||
if (!aScrollableFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIFrame* scrolledFrame = scrollTarget->GetScrolledFrame();
|
||||
nsIFrame* scrolledFrame = aScrollableFrame->GetScrolledFrame();
|
||||
if (!scrolledFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// |scrolledFrame| should at this point be the root content frame of the
|
||||
// nearest ancestor scrollable frame. The element corresponding to this
|
||||
// frame should be the one with the displayport set on it, so find that
|
||||
|
|
@ -2422,6 +2425,49 @@ GetScrollableAncestor(nsIFrame* aTarget)
|
|||
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
|
||||
TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
|
|
@ -2437,6 +2483,7 @@ TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
|||
return;
|
||||
}
|
||||
|
||||
bool waitForRefresh = false;
|
||||
nsTArray<ScrollableLayerGuid> targets;
|
||||
for (size_t i = 0; i < aEvent.touches.Length(); i++) {
|
||||
ScrollableLayerGuid guid(aGuid.mLayersId, 0, FrameMetrics::NULL_SCROLL_ID);
|
||||
|
|
@ -2444,13 +2491,25 @@ TabChild::SendSetTargetAPZCNotification(const WidgetTouchEvent& aEvent,
|
|||
WebWidget(), aEvent.touches[i]->mRefPoint, rootFrame);
|
||||
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(rootFrame, touchPoint,
|
||||
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
|
||||
APZCCallbackHelper::GetOrCreateScrollIdentifiers(
|
||||
GetScrollableAncestor(target),
|
||||
&(guid.mPresShellId),
|
||||
&(guid.mScrollId));
|
||||
nsIScrollableFrame* scrollAncestor = GetScrollableAncestorFrame(target);
|
||||
nsCOMPtr<dom::Element> dpElement = GetDisplayportElementFor(scrollAncestor);
|
||||
|
||||
bool guidIsValid = APZCCallbackHelper::GetOrCreateScrollIdentifiers(
|
||||
dpElement, &(guid.mPresShellId), &(guid.mScrollId));
|
||||
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
|
||||
|
|
|
|||
|
|
@ -988,7 +988,7 @@ nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
|
|||
return GetDisplayPortImpl(aContent, aResult, 1.0f);
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
||||
nsIPresShell* aPresShell,
|
||||
const ScreenMargin& aMargins,
|
||||
|
|
@ -998,7 +998,7 @@ nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
|||
DisplayPortMarginsPropertyData* currentData =
|
||||
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
|
||||
if (currentData && currentData->mPriority > aPriority) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
aContent->SetProperty(nsGkAtoms::DisplayPortMargins,
|
||||
|
|
@ -1022,6 +1022,8 @@ nsLayoutUtils::SetDisplayPortMargins(nsIContent* aContent,
|
|||
rootFrame->SchedulePaint();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2737,20 +2739,22 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// aScrollFrame and aScrollFrameAsScrollable must be non-nullptr
|
||||
// aScrollFrameAsScrollable must be non-nullptr and queryable to an nsIFrame
|
||||
static FrameMetrics
|
||||
CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
||||
nsIScrollableFrame* aScrollFrameAsScrollable) {
|
||||
CalculateFrameMetricsForDisplayPort(nsIScrollableFrame* aScrollFrame) {
|
||||
nsIFrame* frame = do_QueryFrame(aScrollFrame);
|
||||
MOZ_ASSERT(frame);
|
||||
|
||||
// Calculate the metrics necessary for calculating the displayport.
|
||||
// This code has a lot in common with the code in ComputeFrameMetrics();
|
||||
// we may want to refactor this at some point.
|
||||
FrameMetrics metrics;
|
||||
nsPresContext* presContext = aScrollFrame->PresContext();
|
||||
nsPresContext* presContext = frame->PresContext();
|
||||
nsIPresShell* presShell = presContext->PresShell();
|
||||
CSSToLayoutDeviceScale deviceScale(float(nsPresContext::AppUnitsPerCSSPixel())
|
||||
/ presContext->AppUnitsPerDevPixel());
|
||||
float resolution = 1.0f;
|
||||
if (aScrollFrame == presShell->GetRootScrollFrame()) {
|
||||
if (frame == presShell->GetRootScrollFrame()) {
|
||||
// Only the root scrollable frame for a given presShell should pick up
|
||||
// the presShell's resolution. All the other frames are 1.0.
|
||||
resolution = presShell->GetXResolution();
|
||||
|
|
@ -2763,7 +2767,7 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
|||
// and leaving mExtraResolution at 1.
|
||||
LayoutDeviceToLayerScale cumulativeResolution(
|
||||
presShell->GetCumulativeResolution().width
|
||||
* nsLayoutUtils::GetTransformToAncestorScale(aScrollFrame).width);
|
||||
* nsLayoutUtils::GetTransformToAncestorScale(frame).width);
|
||||
|
||||
LayerToParentLayerScale layerToParentLayerScale(1.0f);
|
||||
metrics.mDevPixelsPerCSSPixel = deviceScale;
|
||||
|
|
@ -2773,9 +2777,9 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
|||
|
||||
// Only the size of the composition bounds is relevant to the
|
||||
// displayport calculation, not its origin.
|
||||
nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(aScrollFrame);
|
||||
nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(frame);
|
||||
LayoutDeviceToParentLayerScale compBoundsScale(1.0f);
|
||||
if (aScrollFrame == presShell->GetRootScrollFrame() && presContext->IsRootContentDocument()) {
|
||||
if (frame == presShell->GetRootScrollFrame() && presContext->IsRootContentDocument()) {
|
||||
if (presContext->GetParentPresContext()) {
|
||||
gfxSize res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
|
||||
compBoundsScale = LayoutDeviceToParentLayerScale(res.width, res.height);
|
||||
|
|
@ -2789,17 +2793,33 @@ CalculateFrameMetricsForDisplayPort(nsIFrame* aScrollFrame,
|
|||
* compBoundsScale;
|
||||
|
||||
metrics.SetRootCompositionSize(
|
||||
nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame, false, metrics));
|
||||
nsLayoutUtils::CalculateRootCompositionSize(frame, false, metrics));
|
||||
|
||||
metrics.SetScrollOffset(CSSPoint::FromAppUnits(
|
||||
aScrollFrameAsScrollable->GetScrollPosition()));
|
||||
aScrollFrame->GetScrollPosition()));
|
||||
|
||||
metrics.mScrollableRect = CSSRect::FromAppUnits(
|
||||
nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrameAsScrollable, nullptr));
|
||||
nsLayoutUtils::CalculateScrollableRectForFrame(aScrollFrame, nullptr));
|
||||
|
||||
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
|
||||
nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
||||
nsIFrame* aScrollFrame,
|
||||
|
|
@ -2830,13 +2850,7 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder,
|
|||
|
||||
// If we don't already have a displayport, calculate and set one.
|
||||
if (!haveDisplayPort) {
|
||||
FrameMetrics metrics = CalculateFrameMetricsForDisplayPort(aScrollFrame, scrollableFrame);
|
||||
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);
|
||||
CalculateAndSetDisplayPortMargins(scrollableFrame, nsLayoutUtils::RepaintMode::DoNotRepaint);
|
||||
haveDisplayPort = GetDisplayPort(content, aOutDisplayport);
|
||||
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
|
||||
* when multiple callers specify 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,
|
||||
const ScreenMargin& aMargins,
|
||||
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|
|
||||
* WantsAsyncScroll() and we don't have a scrollable displayport yet (as
|
||||
* tracked by |aBuilder|), calculate and set a display port. Returns true if
|
||||
|
|
|
|||
Loading…
Reference in a new issue