mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 1149555 - Update resize event firing to follow the specs, dispatch right before rAF callbacks, r=dbaron
--HG-- extra : rebase_source : 4828758667591a52ef8d15fa4812c65475ca484f
This commit is contained in:
parent
9b63c77800
commit
bb9c4f4afa
@ -23,6 +23,9 @@ const EXPECTED_REFLOWS = [
|
||||
// Sometimes sessionstore collects data during this test, which causes a sync reflow
|
||||
// (https://bugzilla.mozilla.org/show_bug.cgi?id=892154 will fix this)
|
||||
"ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm",
|
||||
|
||||
// We may get a resize event, see bug 1149555.
|
||||
"PreviewController.prototype.wasResizedSinceLastPreview@resource:///modules/WindowsPreviewPerTab.jsm"
|
||||
];
|
||||
|
||||
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
|
||||
|
@ -72,8 +72,8 @@ var tests = {
|
||||
[chatWidth*2+popupWidth+2, 2, "big enough to fit 2 - nub remains visible as first is still hidden"],
|
||||
[chatWidth*3+popupWidth-2, 2, "one smaller than the size necessary to display all three - first still hidden"],
|
||||
[chatWidth*3+popupWidth+2, 3, "big enough to fit all - all exposed (which removes the nub)"],
|
||||
[chatWidth*3+2, 3, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."],
|
||||
[chatWidth*3-2, 2, "2 pixels less and the first is again collapsed (and the nub re-appears)"],
|
||||
[chatWidth*3+4, 3, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."],
|
||||
[chatWidth*3-4, 2, "4 pixels less and the first is again collapsed (and the nub re-appears)"],
|
||||
[chatWidth*2+popupWidth+2, 2, "back down to just big enough to fit 2"],
|
||||
[chatWidth*2+popupWidth-2, 1, "back down to just not enough to fit 2"],
|
||||
[chatWidth*3+popupWidth+2, 3, "now a large jump to make all 3 visible (ie, affects 2)"],
|
||||
|
@ -48,12 +48,11 @@ addLoadEvent(function() {
|
||||
|
||||
// Now flush out layout on the subdocument, to trigger the resize handler
|
||||
is(bod.getBoundingClientRect().width, 50, "Width of body should still be 50px");
|
||||
|
||||
is(resizeHandlerRan, true, "Resize handler should have run");
|
||||
|
||||
win.removeEventListener("resize", handleResize, false);
|
||||
|
||||
SimpleTest.finish();
|
||||
window.requestAnimationFrame(function() {
|
||||
is(resizeHandlerRan, true, "Resize handler should have run");
|
||||
win.removeEventListener("resize", handleResize, false);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
|
@ -37,23 +37,21 @@ var innerWidthMax = (isWin8 ? 125 : 100);
|
||||
|
||||
function test() {
|
||||
var w = window.open('data:text/html,null', null, 'width=300,height=300');
|
||||
var nbResize = 0;
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
w.onresize = function() {
|
||||
nbResize++;
|
||||
|
||||
if (nbResize == 1) {
|
||||
if (!(w.innerWidth + epsilon >= innerWidthMin &&
|
||||
w.innerWidth - epsilon <= innerWidthMax)) {
|
||||
// We need still another resize event.
|
||||
return;
|
||||
}
|
||||
|
||||
ok(w.innerWidth + epsilon >= innerWidthMin && w.innerWidth - epsilon <= innerWidthMax,
|
||||
"innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
|
||||
ok(w.innerHeight + epsilon >= 100 && w.innerHeight - epsilon <= 100,
|
||||
"innerHeight should be around 100");
|
||||
|
||||
// It's not clear why 2 events are coming...
|
||||
is(nbResize, 2, "We should get 2 events.");
|
||||
if (!(w.innerHeight + epsilon >= 100 &&
|
||||
w.innerHeight - epsilon <= 100)) {
|
||||
// ditto
|
||||
return;
|
||||
}
|
||||
ok(true, "innerWidth should be between " + innerWidthMin + " and " + innerWidthMax);
|
||||
ok(true, "innerHeight should be around 100");
|
||||
|
||||
w.close();
|
||||
|
||||
|
@ -138,10 +138,10 @@ typedef struct CapturingContentInfo {
|
||||
mozilla::StaticRefPtr<nsIContent> mContent;
|
||||
} CapturingContentInfo;
|
||||
|
||||
// d910f009-d209-74c1-6b04-30c83c051c78
|
||||
// b7b89561-4f03-44b3-9afa-b47e7f313ffb
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x025264c6, 0x0b12, 0x4804, \
|
||||
{ 0xa3, 0x3e, 0xb7, 0x73, 0xf2, 0x19, 0x48, 0x90 } }
|
||||
{ 0xb7b89561, 0x4f03, 0x44b3, \
|
||||
{ 0x9a, 0xfa, 0xb4, 0x7e, 0x7f, 0x31, 0x3f, 0xfb } }
|
||||
|
||||
// debug VerifyReflow flags
|
||||
#define VERIFY_REFLOW_ON 0x01
|
||||
@ -1550,6 +1550,8 @@ public:
|
||||
// Whether we should assume all images are visible.
|
||||
virtual bool AssumeAllImagesVisible() = 0;
|
||||
|
||||
virtual void FireResizeEvent() = 0;
|
||||
|
||||
/**
|
||||
* Refresh observer management.
|
||||
*/
|
||||
|
@ -1216,6 +1216,9 @@ PresShell::Destroy()
|
||||
// Revoke any pending events. We need to do this and cancel pending reflows
|
||||
// before we destroy the frame manager, since apparently frame destruction
|
||||
// sometimes spins the event queue when plug-ins are involved(!).
|
||||
if (mResizeEventPending) {
|
||||
rd->RemoveResizeEventFlushObserver(this);
|
||||
}
|
||||
rd->RemoveLayoutFlushObserver(this);
|
||||
if (mHiddenInvalidationObserverRefreshDriver) {
|
||||
mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this);
|
||||
@ -1225,12 +1228,6 @@ PresShell::Destroy()
|
||||
rd->RevokeViewManagerFlush();
|
||||
}
|
||||
|
||||
mResizeEvent.Revoke();
|
||||
if (mAsyncResizeTimerIsActive) {
|
||||
mAsyncResizeEventTimer->Cancel();
|
||||
mAsyncResizeTimerIsActive = false;
|
||||
}
|
||||
|
||||
CancelAllPendingReflows();
|
||||
CancelPostedReflowCallbacks();
|
||||
|
||||
@ -1998,12 +1995,6 @@ PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell)
|
||||
self->UnsuppressPainting();
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell)
|
||||
{
|
||||
static_cast<PresShell*>(aPresShell)->FireResizeEvent();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::ResizeReflowOverride(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
@ -2088,26 +2079,9 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
|
||||
nsRect(0, 0, aWidth, rootFrame->GetRect().height));
|
||||
}
|
||||
|
||||
if (!mIsDestroying && !mResizeEvent.IsPending() &&
|
||||
!mAsyncResizeTimerIsActive) {
|
||||
if (mInResize) {
|
||||
if (!mAsyncResizeEventTimer) {
|
||||
mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
}
|
||||
if (mAsyncResizeEventTimer) {
|
||||
mAsyncResizeTimerIsActive = true;
|
||||
mAsyncResizeEventTimer->InitWithFuncCallback(AsyncResizeEventCallback,
|
||||
this, 15,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
} else {
|
||||
nsRefPtr<nsRunnableMethod<PresShell> > resizeEvent =
|
||||
NS_NewRunnableMethod(this, &PresShell::FireResizeEvent);
|
||||
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
|
||||
mResizeEvent = resizeEvent;
|
||||
mDocument->SetNeedStyleFlush();
|
||||
}
|
||||
}
|
||||
if (!mIsDestroying && !mResizeEventPending) {
|
||||
mResizeEventPending = true;
|
||||
GetPresContext()->RefreshDriver()->AddResizeEventFlushObserver(this);
|
||||
}
|
||||
|
||||
return NS_OK; //XXX this needs to be real. MMP
|
||||
@ -2116,25 +2090,19 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
|
||||
void
|
||||
PresShell::FireResizeEvent()
|
||||
{
|
||||
if (mAsyncResizeTimerIsActive) {
|
||||
mAsyncResizeTimerIsActive = false;
|
||||
mAsyncResizeEventTimer->Cancel();
|
||||
}
|
||||
mResizeEvent.Revoke();
|
||||
|
||||
if (mIsDocumentGone)
|
||||
if (mIsDocumentGone) {
|
||||
return;
|
||||
}
|
||||
|
||||
mResizeEventPending = false;
|
||||
|
||||
//Send resize event from here.
|
||||
WidgetEvent event(true, NS_RESIZE_EVENT);
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
||||
nsPIDOMWindow *window = mDocument->GetWindow();
|
||||
nsPIDOMWindow* window = mDocument->GetWindow();
|
||||
if (window) {
|
||||
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
|
||||
mInResize = true;
|
||||
EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status);
|
||||
mInResize = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4215,13 +4183,6 @@ PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
|
||||
// hold weak refs when calling FlushPendingNotifications(). :(
|
||||
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
|
||||
|
||||
if (mResizeEvent.IsPending()) {
|
||||
FireResizeEvent();
|
||||
if (mIsDestroying) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We need to make sure external resource documents are flushed too (for
|
||||
// example, svg filters that reference a filter in an external document
|
||||
// need the frames in the external document to be constructed for the
|
||||
|
@ -390,6 +390,8 @@ public:
|
||||
|
||||
void SetNextPaintCompressed() { mNextPaintCompressed = true; }
|
||||
|
||||
virtual void FireResizeEvent() override;
|
||||
|
||||
protected:
|
||||
virtual ~PresShell();
|
||||
|
||||
@ -700,9 +702,6 @@ protected:
|
||||
mozilla::LayoutDeviceIntPoint& aTargetPt,
|
||||
nsIWidget *aRootWidget);
|
||||
|
||||
void FireResizeEvent();
|
||||
static void AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell);
|
||||
|
||||
virtual void SynthesizeMouseMove(bool aFromScroll) override;
|
||||
|
||||
PresShell* GetRootPresShell();
|
||||
@ -792,8 +791,6 @@ protected:
|
||||
nsTArray<nsIFrame*> mDirtyRoots;
|
||||
|
||||
nsTArray<nsAutoPtr<DelayedEvent> > mDelayedEvents;
|
||||
nsRevocableEventPtr<nsRunnableMethod<PresShell> > mResizeEvent;
|
||||
nsCOMPtr<nsITimer> mAsyncResizeEventTimer;
|
||||
private:
|
||||
nsIFrame* mCurrentEventFrame;
|
||||
nsCOMPtr<nsIContent> mCurrentEventContent;
|
||||
@ -861,8 +858,7 @@ protected:
|
||||
// have been processed.
|
||||
bool mShouldUnsuppressPainting : 1;
|
||||
|
||||
bool mAsyncResizeTimerIsActive : 1;
|
||||
bool mInResize : 1;
|
||||
bool mResizeEventPending : 1;
|
||||
|
||||
bool mImageVisibilityVisited : 1;
|
||||
|
||||
|
@ -1330,6 +1330,7 @@ nsRefreshDriver::ObserverCount() const
|
||||
// changes can trigger transitions which fire events when they complete, and
|
||||
// layout changes can affect media queries on child documents, triggering
|
||||
// style changes, etc.
|
||||
sum += mResizeEventFlushObservers.Length();
|
||||
sum += mStyleFlushObservers.Length();
|
||||
sum += mLayoutFlushObservers.Length();
|
||||
sum += mFrameRequestCallbackDocs.Length();
|
||||
@ -1627,6 +1628,24 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
AutoRestore<TimeStamp> restoreTickStart(mTickStart);
|
||||
mTickStart = TimeStamp::Now();
|
||||
|
||||
// Resize events should be fired before layout flushes or
|
||||
// calling animation frame callbacks.
|
||||
nsAutoTArray<nsIPresShell*, 16> observers;
|
||||
observers.AppendElements(mResizeEventFlushObservers);
|
||||
for (uint32_t i = observers.Length(); i; --i) {
|
||||
if (!mPresContext || !mPresContext->GetPresShell()) {
|
||||
break;
|
||||
}
|
||||
// Make sure to not process observers which might have been removed
|
||||
// during previous iterations.
|
||||
nsIPresShell* shell = observers[i - 1];
|
||||
if (!mResizeEventFlushObservers.Contains(shell)) {
|
||||
continue;
|
||||
}
|
||||
mResizeEventFlushObservers.RemoveElement(shell);
|
||||
shell->FireResizeEvent();
|
||||
}
|
||||
|
||||
/*
|
||||
* The timer holds a reference to |this| while calling |Notify|.
|
||||
* However, implementations of |WillRefresh| are permitted to destroy
|
||||
|
@ -148,6 +148,22 @@ public:
|
||||
bool AddImageRequest(imgIRequest* aRequest);
|
||||
void RemoveImageRequest(imgIRequest* aRequest);
|
||||
|
||||
/**
|
||||
* Add / remove presshells which have pending resize event.
|
||||
*/
|
||||
void AddResizeEventFlushObserver(nsIPresShell* aShell)
|
||||
{
|
||||
NS_ASSERTION(!mResizeEventFlushObservers.Contains(aShell),
|
||||
"Double-adding resize event flush observer");
|
||||
mResizeEventFlushObservers.AppendElement(aShell);
|
||||
EnsureTimerStarted();
|
||||
}
|
||||
|
||||
void RemoveResizeEventFlushObserver(nsIPresShell* aShell)
|
||||
{
|
||||
mResizeEventFlushObservers.RemoveElement(aShell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add / remove presshells that we should flush style and layout on
|
||||
*/
|
||||
@ -392,6 +408,7 @@ private:
|
||||
RequestTable mRequests;
|
||||
ImageStartTable mStartTable;
|
||||
|
||||
nsAutoTArray<nsIPresShell*, 16> mResizeEventFlushObservers;
|
||||
nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
|
||||
nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
|
||||
nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
|
||||
|
@ -15,6 +15,6 @@ function run() {
|
||||
0);
|
||||
}
|
||||
</script>
|
||||
<body onload="setTimeout(run, 0)">
|
||||
<body onload="setTimeout(run, 20)">
|
||||
<iframe style="visibility:hidden;position:absolute;height:100%;width:100%" src="resize-detector-iframe.html"></iframe>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user