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:
Olli Pettay 2015-05-05 17:56:01 +03:00
parent 9b63c77800
commit bb9c4f4afa
10 changed files with 76 additions and 81 deletions

View File

@ -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") {

View File

@ -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)"],

View File

@ -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>

View File

@ -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();

View File

@ -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.
*/

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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>