Bug 1002332 - Make AnimationTimeline record the last refresh time and use that when there is no refresh driver; r=bz

A document that belongs to an iframe that is display:none as no associated pres
context from which to get a refresh driver. However, in this case
document.timeline.currentTime should still never go backwards (since document
timelines are supposed to be monotonically increasing).

This patch makes AnimationTimeline record the last value returned for the
current time so that if the document becomes display:none we can still return
the most recently used time.
This commit is contained in:
Brian Birtles 2014-07-24 13:37:38 +09:00
parent c7d7b28ccf
commit fb9a1a8fb3
4 changed files with 72 additions and 7 deletions

View File

@ -5,7 +5,6 @@
#include "AnimationTimeline.h"
#include "mozilla/dom/AnimationTimelineBinding.h"
#include "mozilla/TimeStamp.h"
#include "nsContentUtils.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
@ -36,7 +35,18 @@ TimeStamp
AnimationTimeline::GetCurrentTimeStamp() const
{
// Always return the same object to benefit from return-value optimization.
TimeStamp result; // Initializes to null timestamp
TimeStamp result = mLastCurrentTime;
// If we've never been sampled, initialize the current time to the timeline's
// zero time since that is the time we'll use if we don't have a refresh
// driver.
if (result.IsNull()) {
nsRefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
if (!timing) {
return result;
}
result = timing->GetNavigationStartTimeStamp();
}
nsIPresShell* presShell = mDocument->GetShell();
if (MOZ_UNLIKELY(!presShell)) {
@ -49,6 +59,11 @@ AnimationTimeline::GetCurrentTimeStamp() const
}
result = presContext->RefreshDriver()->MostRecentRefresh();
// FIXME: We would like to assert that:
// mLastCurrentTime.IsNull() || result >= mLastCurrentTime
// but due to bug 1043078 this will not be the case when the refresh driver
// is restored from test control.
mLastCurrentTime = result;
return result;
}

View File

@ -9,15 +9,13 @@
#include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h"
#include "js/TypeDecls.h"
#include "nsIDocument.h"
struct JSContext;
namespace mozilla {
class TimeStamp;
namespace dom {
class AnimationTimeline MOZ_FINAL : public nsWrapperCache
@ -44,6 +42,11 @@ protected:
virtual ~AnimationTimeline() { }
nsCOMPtr<nsIDocument> mDocument;
// Store the most recently returned value of current time. This is used
// in cases where we don't have a refresh driver (e.g. because we are in
// a display:none iframe).
mutable mozilla::TimeStamp mLastCurrentTime;
};
} // namespace dom

View File

@ -7,6 +7,7 @@
<script src="/resources/idlharness.js"></script>
<div id="log"></div>
<iframe src="data:text/html;charset=utf-8," width="10" height="10" id="iframe"></iframe>
<iframe src="data:text/html;charset=utf-8,%3Chtml%20style%3D%22display%3Anone%22%3E%3C%2Fhtml%3E" width="10" height="10" id="hidden-iframe"></iframe>
<script type="text/plain" id="AnimationTimeline-IDL">
interface AnimationTimeline {
readonly attribute double? currentTime;
@ -102,4 +103,50 @@ async_test(function(t) {
author: 'Brian Birtles'
});
test(function() {
var hiddenIFrame = document.getElementById('hidden-iframe');
assert_equals(typeof hiddenIFrame.contentDocument.timeline.currentTime,
'number',
'currentTime of an initially hidden subframe\'s timeline is a number');
assert_true(hiddenIFrame.contentDocument.timeline.currentTime >= 0,
'currentTime of an initially hidden subframe\'s timeline is >= 0');
}, 'document.timeline.currentTime hidden subframe test');
async_test(function(t) {
var hiddenIFrame = document.getElementById('hidden-iframe');
// Don't run the test until after the iframe has completed loading or else the
// contentDocument may change.
var testToRunOnLoad = t.step_func(function() {
// Remove display:none
hiddenIFrame.style.display = 'block';
window.getComputedStyle(hiddenIFrame).display;
window.requestAnimationFrame(t.step_func(function() {
assert_true(hiddenIFrame.contentDocument.timeline.currentTime > 0,
'document.timeline.currentTime is positive after removing'
+ ' display:none');
var previousValue = hiddenIFrame.contentDocument.timeline.currentTime;
// Re-introduce display:none
hiddenIFrame.style.display = 'none';
window.getComputedStyle(hiddenIFrame).display;
window.requestAnimationFrame(t.step_func(function() {
assert_true(
hiddenIFrame.contentDocument.timeline.currentTime >= previousValue,
'document.timeline.currentTime does not go backwards after'
+ ' re-setting display:none');
t.done();
}));
}));
});
if (hiddenIFrame.contentDocument.readyState === 'complete') {
testToRunOnLoad();
} else {
hiddenIFrame.addEventListener("load", testToRunOnLoad);
}
}, 'document.timeline.currentTime hidden subframe dynamic test');
</script>

View File

@ -435,8 +435,8 @@ ElementAnimation::CurrentTime() const
// (but not AnimationPlayers) is always 0, these are currently identical.
Nullable<TimeDuration> currentTime = GetLocalTime();
// The current time is currently only going to be null when don't have a
// refresh driver (e.g. because we are in a display:none iframe).
// The current time is only going to be null when we don't have a refresh
// driver or navigation timing object and never did.
//
// Web Animations says that in this case we should use a timeline time of
// 0 (the "effective timeline time") and calculate the current time from that.