mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 569520 part 2. Implement a mozRequestAnimationFrame/mozAnimationStartTime API. r=roc, a=joe
This commit is contained in:
parent
9c767adbfb
commit
456e9e5548
@ -1408,6 +1408,12 @@ public:
|
||||
*/
|
||||
virtual mozilla::dom::Element* GetElementById(const nsAString& aElementId) = 0;
|
||||
|
||||
void ScheduleBeforePaintEvent();
|
||||
void BeforePaintEventFiring()
|
||||
{
|
||||
mHavePendingPaint = PR_FALSE;
|
||||
}
|
||||
|
||||
protected:
|
||||
~nsIDocument()
|
||||
{
|
||||
@ -1547,6 +1553,9 @@ protected:
|
||||
// True if document has ever had script handling object.
|
||||
PRPackedBool mHasHadScriptHandlingObject;
|
||||
|
||||
// True if we're waiting for a before-paint event.
|
||||
PRPackedBool mHavePendingPaint;
|
||||
|
||||
// The document's script global object, the object from which the
|
||||
// document can get its script context and scope. This is the
|
||||
// *inner* window object.
|
||||
|
@ -3074,6 +3074,11 @@ nsDocument::doCreateShell(nsPresContext* aContext,
|
||||
|
||||
mExternalResourceMap.ShowViewers();
|
||||
|
||||
if (mHavePendingPaint) {
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
ScheduleBeforePaintEvent(this);
|
||||
}
|
||||
|
||||
shell.swap(*aInstancePtrResult);
|
||||
|
||||
return NS_OK;
|
||||
@ -3083,6 +3088,9 @@ void
|
||||
nsDocument::DeleteShell()
|
||||
{
|
||||
mExternalResourceMap.HideViewers();
|
||||
if (mHavePendingPaint) {
|
||||
mPresShell->GetPresContext()->RefreshDriver()->RevokeBeforePaintEvent(this);
|
||||
}
|
||||
mPresShell = nsnull;
|
||||
}
|
||||
|
||||
@ -7857,3 +7865,17 @@ nsIDocument::CreateStaticClone(nsISupports* aCloneContainer)
|
||||
mCreatingStaticClone = PR_FALSE;
|
||||
return clonedDoc.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::ScheduleBeforePaintEvent()
|
||||
{
|
||||
if (!mHavePendingPaint) {
|
||||
// We don't want to use GetShell() here, because we want to schedule the
|
||||
// paint even if we're frozen. Either we'll get unfrozen and then the
|
||||
// event will fire, or we'll quietly go away at some point.
|
||||
mHavePendingPaint =
|
||||
!mPresShell ||
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
ScheduleBeforePaintEvent(this);
|
||||
}
|
||||
}
|
||||
|
@ -3509,6 +3509,38 @@ nsGlobalWindow::GetMozPaintCount(PRUint64* aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::MozRequestAnimationFrame()
|
||||
{
|
||||
FORWARD_TO_INNER(MozRequestAnimationFrame, (), NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!mDoc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDoc->ScheduleBeforePaintEvent();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::GetMozAnimationStartTime(PRInt64 *aTime)
|
||||
{
|
||||
FORWARD_TO_INNER(GetMozAnimationStartTime, (aTime), NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (mDoc) {
|
||||
nsIPresShell* presShell = mDoc->GetShell();
|
||||
if (presShell) {
|
||||
*aTime = presShell->GetPresContext()->RefreshDriver()->
|
||||
MostRecentRefreshEpochTime() / PR_USEC_PER_MSEC;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// If all else fails, just be compatible with Date.now()
|
||||
*aTime = JS_Now() / PR_USEC_PER_MSEC;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::SetScreenX(PRInt32 aScreenX)
|
||||
{
|
||||
|
@ -220,4 +220,14 @@ interface nsIDOMWindowInternal : nsIDOMWindow2
|
||||
* been painted to the screen.
|
||||
*/
|
||||
readonly attribute unsigned long long mozPaintCount;
|
||||
|
||||
/**
|
||||
* Request a refresh of this browser window.
|
||||
*/
|
||||
void mozRequestAnimationFrame();
|
||||
|
||||
/**
|
||||
* The current animation start time in milliseconds since the epoch.
|
||||
*/
|
||||
readonly attribute long long mozAnimationStartTime;
|
||||
};
|
||||
|
@ -66,7 +66,6 @@
|
||||
#include "mozFlushType.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include <stdio.h> // for FILE definition
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "nsChangeHint.h"
|
||||
|
||||
class nsIContent;
|
||||
@ -102,6 +101,8 @@ struct nsPoint;
|
||||
struct nsIntPoint;
|
||||
struct nsRect;
|
||||
struct nsIntRect;
|
||||
class nsRefreshDriver;
|
||||
class nsARefreshObserver;
|
||||
|
||||
typedef short SelectionType;
|
||||
typedef PRUint64 nsFrameState;
|
||||
|
@ -47,6 +47,10 @@
|
||||
#include "prlog.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
@ -80,6 +84,14 @@ nsRefreshDriver::MostRecentRefresh() const
|
||||
return mMostRecentRefresh;
|
||||
}
|
||||
|
||||
PRInt64
|
||||
nsRefreshDriver::MostRecentRefreshEpochTime() const
|
||||
{
|
||||
const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
|
||||
|
||||
return mMostRecentRefreshEpochTime;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsRefreshDriver::AddRefreshObserver(nsARefreshObserver *aObserver,
|
||||
mozFlushType aFlushType)
|
||||
@ -143,12 +155,15 @@ nsRefreshDriver::ObserverCount() const
|
||||
}
|
||||
sum += mStyleFlushObservers.Length();
|
||||
sum += mLayoutFlushObservers.Length();
|
||||
sum += mBeforePaintTargets.Length();
|
||||
return sum;
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::UpdateMostRecentRefresh()
|
||||
{
|
||||
// Call JS_Now first, since that can have nonzero latency in some rare cases.
|
||||
mMostRecentRefreshEpochTime = JS_Now();
|
||||
mMostRecentRefresh = TimeStamp::Now();
|
||||
}
|
||||
|
||||
@ -217,6 +232,21 @@ nsRefreshDriver::Notify(nsITimer * /* unused */)
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
// Don't just loop while we have things in mBeforePaintTargets,
|
||||
// the whole point is that event handlers should readd the
|
||||
// target as needed.
|
||||
nsTArray<nsIDocument*> targets;
|
||||
targets.SwapElements(mBeforePaintTargets);
|
||||
PRInt64 eventTime = mMostRecentRefreshEpochTime / PR_USEC_PER_MSEC;
|
||||
for (PRUint32 i = 0; i < targets.Length(); ++i) {
|
||||
targets[i]->BeforePaintEventFiring();
|
||||
}
|
||||
for (PRUint32 i = 0; i < targets.Length(); ++i) {
|
||||
nsEvent ev(PR_TRUE, NS_BEFOREPAINT);
|
||||
ev.time = eventTime;
|
||||
nsEventDispatcher::Dispatch(targets[i], nsnull, &ev);
|
||||
}
|
||||
|
||||
// This is the Flush_Style case.
|
||||
while (!mStyleFlushObservers.IsEmpty() &&
|
||||
mPresContext && mPresContext->GetPresShell()) {
|
||||
@ -280,3 +310,20 @@ nsRefreshDriver::IsRefreshObserver(nsARefreshObserver *aObserver,
|
||||
return array.Contains(aObserver);
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
nsRefreshDriver::ScheduleBeforePaintEvent(nsIDocument* aDocument)
|
||||
{
|
||||
NS_ASSERTION(mBeforePaintTargets.IndexOf(aDocument) ==
|
||||
mBeforePaintTargets.NoIndex,
|
||||
"Shouldn't have a paint event posted for this document");
|
||||
PRBool appended = mBeforePaintTargets.AppendElement(aDocument) != nsnull;
|
||||
EnsureTimerStarted();
|
||||
return appended;
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::RevokeBeforePaintEvent(nsIDocument* aDocument)
|
||||
{
|
||||
mBeforePaintTargets.RemoveElement(aDocument);
|
||||
}
|
||||
|
@ -49,9 +49,11 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
class nsIDocument;
|
||||
|
||||
/**
|
||||
* An abstract base class to be implemented by callers wanting to be
|
||||
@ -91,6 +93,10 @@ public:
|
||||
* the main event loop have the same start time.)
|
||||
*/
|
||||
mozilla::TimeStamp MostRecentRefresh() const;
|
||||
/**
|
||||
* Same thing, but in microseconds since the epoch.
|
||||
*/
|
||||
PRInt64 MostRecentRefreshEpochTime() const;
|
||||
|
||||
/**
|
||||
* Add / remove refresh observers. Returns whether the operation
|
||||
@ -140,6 +146,16 @@ public:
|
||||
return mLayoutFlushObservers.Contains(aShell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a document for which we should fire a MozBeforePaint event.
|
||||
*/
|
||||
PRBool ScheduleBeforePaintEvent(nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Remove a document for which we should fire a MozBeforePaint event.
|
||||
*/
|
||||
void RevokeBeforePaintEvent(nsIDocument* aDocument);
|
||||
|
||||
/**
|
||||
* Tell the refresh driver that it is done driving refreshes and
|
||||
* should stop its timer and forget about its pres context. This may
|
||||
@ -188,6 +204,8 @@ private:
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
mozilla::TimeStamp mMostRecentRefresh; // only valid when mTimer non-null
|
||||
PRInt64 mMostRecentRefreshEpochTime; // same thing as mMostRecentRefresh,
|
||||
// but in microseconds since the epoch.
|
||||
|
||||
nsPresContext *mPresContext; // weak; pres context passed in constructor
|
||||
// and unset in Disconnect
|
||||
@ -198,6 +216,8 @@ private:
|
||||
ObserverArray mObservers[3];
|
||||
nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
|
||||
nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
|
||||
// nsTArray on purpose, because we want to be able to swap.
|
||||
nsTArray<nsIDocument*> mBeforePaintTargets;
|
||||
};
|
||||
|
||||
#endif /* !defined(nsRefreshDriver_h_) */
|
||||
|
@ -196,6 +196,7 @@ _TEST_FILES += \
|
||||
bug467672-5.html \
|
||||
bug467672-5-ref.html \
|
||||
test_bug499538-1.html \
|
||||
test_bug569520.html \
|
||||
test_bug570378-arabic-1a.html \
|
||||
test_bug570378-arabic-1b.html \
|
||||
test_bug570378-arabic-1c.html \
|
||||
|
62
layout/base/tests/test_bug569520.html
Normal file
62
layout/base/tests/test_bug569520.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=569520
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 569520</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=569520">Mozilla Bug 569520</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 569520 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var startNow = Date.now();
|
||||
var start = window.mozAnimationStartTime;
|
||||
var firstListenerTime;
|
||||
var secondListenerTime;
|
||||
|
||||
function secondListener(ev) {
|
||||
secondListenerTime = ev.timeStamp;
|
||||
window.removeEventListener("MozBeforePaint", secondListener, false);
|
||||
|
||||
// They really shouldn't be more than 100ms apart, but we can get weird
|
||||
// effects on slow machines. 5 minutes is our test timeout, though.
|
||||
ok(Math.abs(startNow - start) <= 5 * 60 * 1000, "Bogus animation start time");
|
||||
ok(firstListenerTime >= start, "First listener should fire after start");
|
||||
ok(secondListenerTime > firstListenerTime,
|
||||
"Second listener should fire after first listener");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function firstListener(ev) {
|
||||
firstListenerTime = ev.timeStamp;
|
||||
window.removeEventListener("MozBeforePaint", firstListener, false);
|
||||
window.addEventListener("MozBeforePaint", secondListener, false);
|
||||
mozRequestAnimationFrame();
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
setTimeout(function() {
|
||||
window.addEventListener("MozBeforePaint", firstListener, false);
|
||||
mozRequestAnimationFrame();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user