зеркало из https://github.com/mozilla/pjs.git
Merge backout.
This commit is contained in:
Коммит
cb4f658d24
|
@ -50,6 +50,7 @@
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
#include "ImageLayers.h"
|
#include "ImageLayers.h"
|
||||||
#include "nsAudioStream.h"
|
#include "nsAudioStream.h"
|
||||||
|
#include "nsTimeRanges.h"
|
||||||
|
|
||||||
// Define to output information on decoding and painting framerate
|
// Define to output information on decoding and painting framerate
|
||||||
/* #define DEBUG_FRAME_RATE 1 */
|
/* #define DEBUG_FRAME_RATE 1 */
|
||||||
|
@ -624,6 +625,12 @@ protected:
|
||||||
// a media and element same-origin check.
|
// a media and element same-origin check.
|
||||||
PRBool mAllowAudioData;
|
PRBool mAllowAudioData;
|
||||||
|
|
||||||
|
// Range of time played.
|
||||||
|
nsTimeRanges mPlayed;
|
||||||
|
|
||||||
|
// Temporary variable for storing a time, when the stream starts to play
|
||||||
|
double mCurrentPlayRangeStart;
|
||||||
|
|
||||||
// If true then we have begun downloading the media content.
|
// If true then we have begun downloading the media content.
|
||||||
// Set to false when completed, or not yet started.
|
// Set to false when completed, or not yet started.
|
||||||
PRPackedBool mBegun;
|
PRPackedBool mBegun;
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include "nsIDOMHTMLMediaElement.h"
|
#include "nsIDOMHTMLMediaElement.h"
|
||||||
#include "nsIDOMHTMLSourceElement.h"
|
#include "nsIDOMHTMLSourceElement.h"
|
||||||
#include "nsHTMLMediaElement.h"
|
#include "nsHTMLMediaElement.h"
|
||||||
#include "nsTimeRanges.h"
|
|
||||||
#include "nsGenericHTMLElement.h"
|
#include "nsGenericHTMLElement.h"
|
||||||
#include "nsPresContext.h"
|
#include "nsPresContext.h"
|
||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
|
@ -1092,6 +1091,16 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime)
|
||||||
{
|
{
|
||||||
StopSuspendingAfterFirstFrame();
|
StopSuspendingAfterFirstFrame();
|
||||||
|
|
||||||
|
if (mCurrentPlayRangeStart != -1) {
|
||||||
|
double oldCurrentTime = 0;
|
||||||
|
GetCurrentTime(&oldCurrentTime);
|
||||||
|
LOG(PR_LOG_DEBUG, ("Adding a range: [%f, %f]", mCurrentPlayRangeStart, oldCurrentTime));
|
||||||
|
// Multiple seek without playing
|
||||||
|
if (mCurrentPlayRangeStart != oldCurrentTime) {
|
||||||
|
mPlayed.Add(mCurrentPlayRangeStart, oldCurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!mDecoder) {
|
if (!mDecoder) {
|
||||||
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no decoder", this, aCurrentTime));
|
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no decoder", this, aCurrentTime));
|
||||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
|
@ -1121,6 +1130,9 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime)
|
||||||
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime));
|
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime));
|
||||||
nsresult rv = mDecoder->Seek(clampedTime);
|
nsresult rv = mDecoder->Seek(clampedTime);
|
||||||
|
|
||||||
|
// Start a new range at position we seeked to
|
||||||
|
mCurrentPlayRangeStart = clampedTime;
|
||||||
|
|
||||||
// We changed whether we're seeking so we need to AddRemoveSelfReference
|
// We changed whether we're seeking so we need to AddRemoveSelfReference
|
||||||
AddRemoveSelfReference();
|
AddRemoveSelfReference();
|
||||||
|
|
||||||
|
@ -1142,6 +1154,35 @@ NS_IMETHODIMP nsHTMLMediaElement::GetPaused(PRBool *aPaused)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* readonly attribute nsIDOMHTMLTimeRanges played; */
|
||||||
|
NS_IMETHODIMP nsHTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed)
|
||||||
|
{
|
||||||
|
nsRefPtr<nsTimeRanges> ranges = new nsTimeRanges();
|
||||||
|
|
||||||
|
PRUint32 timeRangeCount = 0;
|
||||||
|
mPlayed.GetLength(&timeRangeCount);
|
||||||
|
for (PRUint32 i = 0; i < timeRangeCount; i++) {
|
||||||
|
double begin;
|
||||||
|
double end;
|
||||||
|
mPlayed.Start(i, &begin);
|
||||||
|
mPlayed.End(i, &end);
|
||||||
|
ranges->Add(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrentPlayRangeStart != -1.0) {
|
||||||
|
double now = 0.0;
|
||||||
|
GetCurrentTime(&now);
|
||||||
|
if (mCurrentPlayRangeStart != now) {
|
||||||
|
ranges->Add(mCurrentPlayRangeStart, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ranges->Normalize();
|
||||||
|
|
||||||
|
ranges.forget(aPlayed);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* void pause (); */
|
/* void pause (); */
|
||||||
NS_IMETHODIMP nsHTMLMediaElement::Pause()
|
NS_IMETHODIMP nsHTMLMediaElement::Pause()
|
||||||
{
|
{
|
||||||
|
@ -1280,6 +1321,7 @@ nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||||
mMediaSize(-1,-1),
|
mMediaSize(-1,-1),
|
||||||
mLastCurrentTime(0.0),
|
mLastCurrentTime(0.0),
|
||||||
mAllowAudioData(PR_FALSE),
|
mAllowAudioData(PR_FALSE),
|
||||||
|
mCurrentPlayRangeStart(-1.0),
|
||||||
mBegun(PR_FALSE),
|
mBegun(PR_FALSE),
|
||||||
mLoadedFirstFrame(PR_FALSE),
|
mLoadedFirstFrame(PR_FALSE),
|
||||||
mAutoplaying(PR_TRUE),
|
mAutoplaying(PR_TRUE),
|
||||||
|
@ -1380,6 +1422,10 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mCurrentPlayRangeStart == -1.0) {
|
||||||
|
GetCurrentTime(&mCurrentPlayRangeStart);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: If the playback has ended, then the user agent must set
|
// TODO: If the playback has ended, then the user agent must set
|
||||||
// seek to the effective start.
|
// seek to the effective start.
|
||||||
// TODO: The playback rate must be set to the default playback rate.
|
// TODO: The playback rate must be set to the default playback rate.
|
||||||
|
@ -2034,6 +2080,13 @@ void nsHTMLMediaElement::PlaybackEnded()
|
||||||
// We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
|
// We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
|
||||||
AddRemoveSelfReference();
|
AddRemoveSelfReference();
|
||||||
|
|
||||||
|
double end = 0.0;
|
||||||
|
GetCurrentTime(&end);
|
||||||
|
if (mCurrentPlayRangeStart != end) {
|
||||||
|
mPlayed.Add(mCurrentPlayRangeStart, end);
|
||||||
|
}
|
||||||
|
mCurrentPlayRangeStart = -1.0;
|
||||||
|
|
||||||
if (mDecoder && mDecoder->IsInfinite()) {
|
if (mDecoder && mDecoder->IsInfinite()) {
|
||||||
LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the stream", this));
|
LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the stream", this));
|
||||||
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
||||||
|
@ -2455,7 +2508,7 @@ void nsHTMLMediaElement::NotifyAddedSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A load was paused in the resource selection algorithm, waiting for
|
// A load was paused in the resource selection algorithm, waiting for
|
||||||
// a new source child to be added, resume the resource selction algorithm.
|
// a new source child to be added, resume the resource selection algorithm.
|
||||||
if (mLoadWaitStatus == WAITING_FOR_SOURCE) {
|
if (mLoadWaitStatus == WAITING_FOR_SOURCE) {
|
||||||
QueueLoadFromSourceTask();
|
QueueLoadFromSourceTask();
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,3 +85,28 @@ void
|
||||||
nsTimeRanges::Add(double aStart, double aEnd) {
|
nsTimeRanges::Add(double aStart, double aEnd) {
|
||||||
mRanges.AppendElement(TimeRange(aStart,aEnd));
|
mRanges.AppendElement(TimeRange(aStart,aEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsTimeRanges::Normalize() {
|
||||||
|
if (mRanges.Length() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nsAutoTArray<TimeRange, 4> normalized;
|
||||||
|
|
||||||
|
mRanges.Sort(CompareTimeRanges());
|
||||||
|
|
||||||
|
// This merges the intervals
|
||||||
|
TimeRange current(mRanges[0]);
|
||||||
|
for (PRUint32 i = 1; i < mRanges.Length(); i++) {
|
||||||
|
if (current.mEnd >= mRanges[i].mStart) {
|
||||||
|
current.mEnd = NS_MAX(current.mEnd, mRanges[i].mEnd);
|
||||||
|
} else {
|
||||||
|
normalized.AppendElement(current);
|
||||||
|
current = mRanges[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalized.AppendElement(current);
|
||||||
|
|
||||||
|
mRanges = normalized;
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,9 @@ public:
|
||||||
|
|
||||||
void Add(double aStart, double aEnd);
|
void Add(double aStart, double aEnd);
|
||||||
|
|
||||||
|
// See <http://www.whatwg.org/html/#normalized-timeranges-object>.
|
||||||
|
void Normalize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct TimeRange {
|
struct TimeRange {
|
||||||
|
@ -65,6 +68,21 @@ private:
|
||||||
double mEnd;
|
double mEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CompareTimeRanges
|
||||||
|
{
|
||||||
|
PRBool Equals(const TimeRange& tr1, const TimeRange& tr2) const
|
||||||
|
{
|
||||||
|
return tr1.mStart == tr2.mStart && tr1.mEnd == tr2.mEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here, we aim at time range normalization. That why we order only by start
|
||||||
|
// time, since the ranges can overlap.
|
||||||
|
PRBool LessThan(const TimeRange& tr1, const TimeRange& tr2) const
|
||||||
|
{
|
||||||
|
return tr1.mStart < tr2.mStart;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
nsAutoTArray<TimeRange,4> mRanges;
|
nsAutoTArray<TimeRange,4> mRanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,7 @@ _TEST_FILES = \
|
||||||
test_paused_after_ended.html \
|
test_paused_after_ended.html \
|
||||||
test_play_events.html \
|
test_play_events.html \
|
||||||
test_play_events_2.html \
|
test_play_events_2.html \
|
||||||
|
test_played.html \
|
||||||
test_playback.html \
|
test_playback.html \
|
||||||
test_playback_errors.html \
|
test_playback_errors.html \
|
||||||
test_preload_actions.html \
|
test_preload_actions.html \
|
||||||
|
|
|
@ -23,6 +23,14 @@ var gProgressTests = [
|
||||||
{ name:"bogus.duh", type:"bogus/duh" }
|
{ name:"bogus.duh", type:"bogus/duh" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Used by test_played
|
||||||
|
var gPlayedTests = [
|
||||||
|
{ name:"big.wav", type:"audio/x-wav", duration:9.0, size:102444 },
|
||||||
|
{ name:"sound.ogg", type:"audio/ogg", duration:4.0, size:2603 },
|
||||||
|
{ name:"seek.ogv", type:"video/ogg", duration:3.966, size:285310 },
|
||||||
|
{ name:"seek.webm", type:"video/webm", duration:3.966 }
|
||||||
|
];
|
||||||
|
|
||||||
// Used by test_mozLoadFrom. Need one test file per decoder backend, plus
|
// Used by test_mozLoadFrom. Need one test file per decoder backend, plus
|
||||||
// anything for testing clone-specific bugs.
|
// anything for testing clone-specific bugs.
|
||||||
var gCloneTests = gSmallTests.concat([
|
var gCloneTests = gSmallTests.concat([
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test played member for media elements</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
<script type="text/javascript" src="manifest.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id='test'>
|
||||||
|
<script class="testbody" type='application/javascript;version=1.8'>
|
||||||
|
|
||||||
|
let manager = new MediaTestManager;
|
||||||
|
|
||||||
|
function finish_test(element) {
|
||||||
|
if (element.parentNode)
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
element.src = "";
|
||||||
|
manager.finished(element.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that a file has been played in its entirety
|
||||||
|
function check_full_file_played(element) {
|
||||||
|
element.addEventListener('ended', function() {
|
||||||
|
let interval_count = element.played.length;
|
||||||
|
is(interval_count, 1, "normal play: a.played.length must be 1");
|
||||||
|
is(element.played.start(0), 0, "start time shall be 0");
|
||||||
|
is(element.played.end(0), element.duration, "end time shall be duration");
|
||||||
|
finish_test(element);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
// Without playing, check that player.played.length == 0
|
||||||
|
{
|
||||||
|
setup : function(element) {
|
||||||
|
element.addEventListener("loadedmetadata", function() {
|
||||||
|
is(element.played.length, 0, "audio: initial played.length equals zero");
|
||||||
|
finish_test(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Play the file, test the range we have
|
||||||
|
{
|
||||||
|
setup : function(element) {
|
||||||
|
check_full_file_played(element);
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Play the first half of the file, pause, play
|
||||||
|
// and check we have only one range
|
||||||
|
{
|
||||||
|
setup : function (element) {
|
||||||
|
let onEnded = function() {
|
||||||
|
element.pause();
|
||||||
|
element.currentTime = 0;
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
element.addEventListener("ended", onEnded, false);
|
||||||
|
check_full_file_played(element);
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Play the first half of the file, seek back, while
|
||||||
|
// continuing to play. We shall have only one range
|
||||||
|
{
|
||||||
|
setup : function (element) {
|
||||||
|
let onTimeUpdate = function() {
|
||||||
|
if (element.currentTime > element.duration / 2) {
|
||||||
|
element.removeEventListener("timeupdate", onTimeUpdate, false);
|
||||||
|
element.currentTime = element.duration / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.addEventListener("timeupdate", onTimeUpdate, false);
|
||||||
|
check_full_file_played(element);
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Play and seek to have two ranges, and check that, as well a
|
||||||
|
// boundaries
|
||||||
|
{
|
||||||
|
setup : function (element) {
|
||||||
|
let onTimeUpdate = function() {
|
||||||
|
if (element.currentTime > element.duration / 2) {
|
||||||
|
element.removeEventListener("timeupdate", onTimeUpdate, false);
|
||||||
|
element.pause();
|
||||||
|
element.currentTime += element.duration / 10;
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element.addEventListener("loadedmetadata", function() {
|
||||||
|
element.addEventListener("timeupdate", onTimeUpdate, false);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
|
||||||
|
element.addEventListener("ended", function() {
|
||||||
|
if (element.played.length > 1) {
|
||||||
|
is(element.played.length, 2, "element.played.length == 2");
|
||||||
|
var guess = element.played.end(0) + element.duration / 10.0;
|
||||||
|
ok(rangeCheck(element.played.start(1), guess), "we should have seeked forward by one tenth of the duration");
|
||||||
|
is(element.played.end(1), element.duration, "end of second range shall be the total duration");
|
||||||
|
}
|
||||||
|
is(element.played.start(0), 0, "start of first range shall be 0");
|
||||||
|
finish_test(element);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Play and seek to have to overlapping ranges. They should be merged, to a
|
||||||
|
// range spanning all the test audio file.
|
||||||
|
{
|
||||||
|
setup : function (element) {
|
||||||
|
let onTimeUpdate = function() {
|
||||||
|
if (element.currentTime > element.duration / 2) {
|
||||||
|
element.removeEventListener("timeupdate", onTimeUpdate, false);
|
||||||
|
element.currentTime = element.duration / 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
element.addEventListener("loadedmetadata", function() {
|
||||||
|
element.addEventListener("timeupdate", onTimeUpdate, false);
|
||||||
|
check_full_file_played(element);
|
||||||
|
element.play();
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Play to create two ranges, in the reverse order. check that they are sorted.
|
||||||
|
{
|
||||||
|
setup : function (element) {
|
||||||
|
function end() {
|
||||||
|
element.pause();
|
||||||
|
let p = element.played;
|
||||||
|
ok(p.length >= 1, "There should be at least one range");
|
||||||
|
is(p.start(0), element.duration / 6,
|
||||||
|
"Start of first range should be the sixth of the duration");
|
||||||
|
ok(p.end(p.length - 1) > 5 * element.duration / 6,
|
||||||
|
"End of last range should be greater that five times the sixth of the duration");
|
||||||
|
finish_test(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseseekrestart() {
|
||||||
|
element.pause();
|
||||||
|
element.currentTime = element.duration / 6;
|
||||||
|
element.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimeUpdate_pauseseekrestart() {
|
||||||
|
if (element.currentTime > 5 * element.duration / 6) {
|
||||||
|
element.removeEventListener("timeupdate", onTimeUpdate_pauseseekrestart, false);
|
||||||
|
pauseseekrestart();
|
||||||
|
element.addEventListener("timeupdate", onTimeUpdate_end, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimeUpdate_end() {
|
||||||
|
if (element.currentTime > 3 * element.duration / 6) {
|
||||||
|
element.removeEventListener("timeupdate", onTimeUpdate_end, false);
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element.addEventListener("timeupdate", onTimeUpdate_pauseseekrestart, false);
|
||||||
|
|
||||||
|
element.addEventListener('loadedmetadata', function() {
|
||||||
|
element.currentTime = 4 * element.duration / 6;
|
||||||
|
element.play();
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Seek repeatedly without playing. No range should appear.
|
||||||
|
{
|
||||||
|
setup : function(element) {
|
||||||
|
let index = 1;
|
||||||
|
|
||||||
|
element.addEventListener('ended', function() {
|
||||||
|
is(element.played.length, 0, "element.played.length should be 0");
|
||||||
|
finish_test(element);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
element.addEventListener('seeked', function() {
|
||||||
|
index++;
|
||||||
|
element.currentTime = index * element.duration / 5;
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
element.addEventListener('loadedmetadata', function() {
|
||||||
|
element.currentTime = element.duration / 5;
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function rangeCheck(n1, n2) {
|
||||||
|
var THRESHOLD = 0.35;
|
||||||
|
var diff = Math.abs(n1 - n2);
|
||||||
|
return diff < THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTestArray(tests) {
|
||||||
|
var A = [];
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
for (var k = 0; k < gPlayedTests.length; k++) {
|
||||||
|
A.push({
|
||||||
|
setup : tests[i].setup,
|
||||||
|
name : gPlayedTests[k].name,
|
||||||
|
type : gPlayedTests[k].type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return A;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTest(test, token) {
|
||||||
|
var elemType = /^audio/.test(test.type) ? "audio" : "video";
|
||||||
|
var element = document.createElement(elemType);
|
||||||
|
element.src = test.name;
|
||||||
|
element.token = token;
|
||||||
|
test.setup(element);
|
||||||
|
manager.started(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.runTests(createTestArray(tests), startTest);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -52,7 +52,7 @@
|
||||||
* @status UNDER_DEVELOPMENT
|
* @status UNDER_DEVELOPMENT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[scriptable, uuid(f0d4977c-9632-4fab-bc9b-91c250a6ef96)]
|
[scriptable, uuid(1f2437f1-6037-40c4-bfb6-105c6c60f0ca)]
|
||||||
interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement
|
interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement
|
||||||
{
|
{
|
||||||
// Setup the audio stream for writing
|
// Setup the audio stream for writing
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
#endif
|
#endif
|
||||||
%}
|
%}
|
||||||
|
|
||||||
[scriptable, uuid(d8213322-46d8-47ca-a15c-2abae47ddfde)]
|
[scriptable, uuid(c8a5f714-97de-4e2c-8394-2397870224bb)]
|
||||||
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
|
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
|
||||||
{
|
{
|
||||||
// error state
|
// error state
|
||||||
|
@ -89,6 +89,7 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
|
||||||
attribute double currentTime;
|
attribute double currentTime;
|
||||||
readonly attribute double duration;
|
readonly attribute double duration;
|
||||||
readonly attribute boolean paused;
|
readonly attribute boolean paused;
|
||||||
|
readonly attribute nsIDOMTimeRanges played;
|
||||||
readonly attribute boolean ended;
|
readonly attribute boolean ended;
|
||||||
readonly attribute boolean mozAutoplayEnabled;
|
readonly attribute boolean mozAutoplayEnabled;
|
||||||
attribute boolean autoplay;
|
attribute boolean autoplay;
|
||||||
|
|
|
@ -48,15 +48,15 @@
|
||||||
* @status UNDER_DEVELOPMENT
|
* @status UNDER_DEVELOPMENT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[scriptable, uuid(00c757ec-db7b-477e-95cd-b2a03b0f8634)]
|
[scriptable, uuid(169f0ff1-511a-453d-86b6-346c1e936122)]
|
||||||
interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
|
interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
|
||||||
{
|
{
|
||||||
attribute long width;
|
attribute long width;
|
||||||
attribute long height;
|
attribute long height;
|
||||||
readonly attribute unsigned long videoWidth;
|
readonly attribute unsigned long videoWidth;
|
||||||
readonly attribute unsigned long videoHeight;
|
readonly attribute unsigned long videoHeight;
|
||||||
attribute DOMString poster;
|
attribute DOMString poster;
|
||||||
|
|
||||||
// A count of the number of video frames that have demuxed from the media
|
// A count of the number of video frames that have demuxed from the media
|
||||||
// resource. If we were playing perfectly, we'd be able to paint this many
|
// resource. If we were playing perfectly, we'd be able to paint this many
|
||||||
// frames.
|
// frames.
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
// |jit-test| debug;mjit
|
// |jit-test| debug;mjit
|
||||||
|
|
||||||
/*
|
o = { toString:function() { return evalInFrame(1, "x") } }
|
||||||
* NOTE: this evalInFrame is explicitly exposing an optimization artifact that
|
var x = 'C';
|
||||||
* InvokeSessionGuard leaves the callee frame on the stack between invocations.
|
|
||||||
* If this ever gets fixed or InvokeSessionGuard gets removed, this test will
|
|
||||||
* fail and it can be removed.
|
|
||||||
*/
|
|
||||||
o = { toString:function() { return evalInFrame(1, "arguments; x") } }
|
|
||||||
var s = "aaaaaaaaaa".replace(/a/g, function() { var x = 'B'; return o });
|
var s = "aaaaaaaaaa".replace(/a/g, function() { var x = 'B'; return o });
|
||||||
assertEq(s, "BBBBBBBBBB");
|
assertEq(s, "CCCCCCCCCC");
|
||||||
|
|
|
@ -4473,7 +4473,7 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *p
|
||||||
if (script) {
|
if (script) {
|
||||||
scriptObj = js_NewScriptObject(cx, script);
|
scriptObj = js_NewScriptObject(cx, script);
|
||||||
if (!scriptObj)
|
if (!scriptObj)
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 3);
|
||||||
}
|
}
|
||||||
LAST_FRAME_CHECKS(cx, scriptObj);
|
LAST_FRAME_CHECKS(cx, scriptObj);
|
||||||
return scriptObj;
|
return scriptObj;
|
||||||
|
@ -4660,7 +4660,7 @@ CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||||
|
|
||||||
JSObject *scriptObj = js_NewScriptObject(cx, script);
|
JSObject *scriptObj = js_NewScriptObject(cx, script);
|
||||||
if (!scriptObj)
|
if (!scriptObj)
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 4);
|
||||||
|
|
||||||
return scriptObj;
|
return scriptObj;
|
||||||
}
|
}
|
||||||
|
@ -4967,7 +4967,7 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj,
|
||||||
|
|
||||||
bool ok = ExternalExecute(cx, script, *obj, Valueify(rval));
|
bool ok = ExternalExecute(cx, script, *obj, Valueify(rval));
|
||||||
LAST_FRAME_CHECKS(cx, ok);
|
LAST_FRAME_CHECKS(cx, ok);
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 5);
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1125,7 +1125,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg,
|
||||||
|
|
||||||
bool ok = Execute(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, Valueify(rval));
|
bool ok = Execute(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, Valueify(rval));
|
||||||
|
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 6);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1586,8 +1586,14 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
|
||||||
fun->u.i.wrapper = JSPackedBool((firstword >> 1) & 1);
|
fun->u.i.wrapper = JSPackedBool((firstword >> 1) & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!js_XDRScript(xdr, &fun->u.i.script))
|
/*
|
||||||
|
* Don't directly store into fun->u.i.script because we want this to happen
|
||||||
|
* at the same time as we set the script's owner.
|
||||||
|
*/
|
||||||
|
JSScript *script = fun->u.i.script;
|
||||||
|
if (!js_XDRScript(xdr, &script))
|
||||||
return false;
|
return false;
|
||||||
|
fun->u.i.script = script;
|
||||||
|
|
||||||
if (xdr->mode == JSXDR_DECODE) {
|
if (xdr->mode == JSXDR_DECODE) {
|
||||||
*objp = FUN_OBJECT(fun);
|
*objp = FUN_OBJECT(fun);
|
||||||
|
@ -2474,9 +2480,10 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
||||||
JS_ASSERT(script->compartment != cx->compartment);
|
JS_ASSERT(script->compartment != cx->compartment);
|
||||||
JS_OPT_ASSERT(script->ownerObject == fun);
|
JS_OPT_ASSERT(script->ownerObject == fun);
|
||||||
|
|
||||||
cfun->u.i.script = js_CloneScript(cx, script);
|
JSScript *cscript = js_CloneScript(cx, script);
|
||||||
if (!cfun->script())
|
if (!cscript)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
cfun->u.i.script = cscript;
|
||||||
cfun->script()->setOwnerObject(cfun);
|
cfun->script()->setOwnerObject(cfun);
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
cfun->script()->owner = NULL;
|
cfun->script()->owner = NULL;
|
||||||
|
|
|
@ -709,6 +709,9 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
|
||||||
savedCallee_ = args_.calleev() = calleev;
|
savedCallee_ = args_.calleev() = calleev;
|
||||||
savedThis_ = args_.thisv() = thisv;
|
savedThis_ = args_.thisv() = thisv;
|
||||||
|
|
||||||
|
/* If anyone (through jsdbgapi) finds this frame, make it safe. */
|
||||||
|
MakeRangeGCSafe(args_.argv(), args_.argc());
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* Hoist dynamic checks from scripted Invoke. */
|
/* Hoist dynamic checks from scripted Invoke. */
|
||||||
if (!calleev.isObject())
|
if (!calleev.isObject())
|
||||||
|
|
|
@ -1142,7 +1142,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
|
||||||
|
|
||||||
late_error:
|
late_error:
|
||||||
if (script) {
|
if (script) {
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 7);
|
||||||
script = NULL;
|
script = NULL;
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -754,7 +754,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (xdr->mode == JSXDR_DECODE) {
|
if (xdr->mode == JSXDR_DECODE) {
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 1);
|
||||||
*scriptp = NULL;
|
*scriptp = NULL;
|
||||||
}
|
}
|
||||||
xdr->script = oldscript;
|
xdr->script = oldscript;
|
||||||
|
@ -1270,7 +1270,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
||||||
return script;
|
return script;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script, 2);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,7 +1345,7 @@ CheckCompartmentScripts(JSCompartment *comp)
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DestroyScript(JSContext *cx, JSScript *script, JSObject *owner)
|
DestroyScript(JSContext *cx, JSScript *script, JSObject *owner, uint32 caller)
|
||||||
{
|
{
|
||||||
CheckScript(script, NULL);
|
CheckScript(script, NULL);
|
||||||
CheckScriptOwner(script, owner);
|
CheckScriptOwner(script, owner);
|
||||||
|
@ -1408,16 +1408,17 @@ DestroyScript(JSContext *cx, JSScript *script, JSObject *owner)
|
||||||
if (script->sourceMap)
|
if (script->sourceMap)
|
||||||
cx->free_(script->sourceMap);
|
cx->free_(script->sourceMap);
|
||||||
|
|
||||||
memset(script, JS_FREE_PATTERN, script->totalSize());
|
memset(script, 0xdb, script->totalSize());
|
||||||
|
*(uint32 *)script = caller;
|
||||||
cx->free_(script);
|
cx->free_(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_DestroyScript(JSContext *cx, JSScript *script)
|
js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!cx->runtime->gcRunning);
|
JS_ASSERT(!cx->runtime->gcRunning);
|
||||||
js_CallDestroyScriptHook(cx, script);
|
js_CallDestroyScriptHook(cx, script);
|
||||||
DestroyScript(cx, script, JS_NEW_SCRIPT);
|
DestroyScript(cx, script, JS_NEW_SCRIPT, caller);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1425,14 +1426,14 @@ js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->runtime->gcRunning);
|
JS_ASSERT(cx->runtime->gcRunning);
|
||||||
js_CallDestroyScriptHook(cx, script);
|
js_CallDestroyScriptHook(cx, script);
|
||||||
DestroyScript(cx, script, owner);
|
DestroyScript(cx, script, owner, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_DestroyCachedScript(JSContext *cx, JSScript *script)
|
js_DestroyCachedScript(JSContext *cx, JSScript *script)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->runtime->gcRunning);
|
JS_ASSERT(cx->runtime->gcRunning);
|
||||||
DestroyScript(cx, script, JS_CACHED_SCRIPT);
|
DestroyScript(cx, script, JS_CACHED_SCRIPT, 101);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -733,7 +733,7 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
|
||||||
* only on the current thread.
|
* only on the current thread.
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
js_DestroyScript(JSContext *cx, JSScript *script);
|
js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner);
|
js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner);
|
||||||
|
|
|
@ -70,19 +70,26 @@ JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)()));
|
||||||
static JS_NEVER_INLINE void
|
static JS_NEVER_INLINE void
|
||||||
CrashInJS()
|
CrashInJS()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* We write 123 here so that the machine code for this function is
|
||||||
|
* unique. Otherwise the linker, trying to be smart, might use the
|
||||||
|
* same code for CrashInJS and for some other function. That
|
||||||
|
* messes up the signature in minidumps.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
/*
|
/*
|
||||||
* We used to call DebugBreak() on Windows, but amazingly, it causes
|
* We used to call DebugBreak() on Windows, but amazingly, it causes
|
||||||
* the MSVS 2010 debugger not to be able to recover a call stack.
|
* the MSVS 2010 debugger not to be able to recover a call stack.
|
||||||
*/
|
*/
|
||||||
*((int *) NULL) = 0;
|
*((int *) NULL) = 123;
|
||||||
exit(3);
|
exit(3);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
/*
|
/*
|
||||||
* On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
|
* On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
|
||||||
* trapped.
|
* trapped.
|
||||||
*/
|
*/
|
||||||
*((int *) NULL) = 0; /* To continue from here in GDB: "return" then "continue". */
|
*((int *) NULL) = 123; /* To continue from here in GDB: "return" then "continue". */
|
||||||
raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */
|
raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */
|
||||||
#else
|
#else
|
||||||
raise(SIGABRT); /* To continue from here in GDB: "signal 0". */
|
raise(SIGABRT); /* To continue from here in GDB: "signal 0". */
|
||||||
|
|
|
@ -720,7 +720,7 @@ JS_XDRScriptObject(JSXDRState *xdr, JSObject **scriptObjp)
|
||||||
js_CallNewScriptHook(xdr->cx, script, NULL);
|
js_CallNewScriptHook(xdr->cx, script, NULL);
|
||||||
*scriptObjp = js_NewScriptObject(xdr->cx, script);
|
*scriptObjp = js_NewScriptObject(xdr->cx, script);
|
||||||
if (!*scriptObjp) {
|
if (!*scriptObjp) {
|
||||||
js_DestroyScript(xdr->cx, script);
|
js_DestroyScript(xdr->cx, script, 8);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -963,6 +963,12 @@ StackIter::settleOnNewState()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Censor pushed-but-not-active frames from InvokeSessionGuard. */
|
||||||
|
if (containsCall && !calls_->active() && calls_->argv() == fp_->actualArgs()) {
|
||||||
|
popFrame();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As an optimization, there is no CallArgsList element pushed for
|
* As an optimization, there is no CallArgsList element pushed for
|
||||||
* natives called directly by a script (compiled or interpreted).
|
* natives called directly by a script (compiled or interpreted).
|
||||||
|
|
|
@ -116,30 +116,31 @@ JSString::charsHeapSize()
|
||||||
return length() * sizeof(jschar);
|
return length() * sizeof(jschar);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE size_t
|
static JS_ALWAYS_INLINE bool
|
||||||
RopeCapacityFor(size_t length)
|
AllocChars(JSContext *maybecx, size_t length, jschar **chars, size_t *capacity)
|
||||||
{
|
{
|
||||||
static const size_t ROPE_DOUBLING_MAX = 1024 * 1024;
|
/*
|
||||||
|
* String length doesn't include the null char, so include it here before
|
||||||
|
* doubling. Adding the null char after doubling would interact poorly with
|
||||||
|
* round-up malloc schemes.
|
||||||
|
*/
|
||||||
|
size_t numChars = length + 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grow by 12.5% if the buffer is very large. Otherwise, round up to the
|
* Grow by 12.5% if the buffer is very large. Otherwise, round up to the
|
||||||
* next power of 2. This is similar to what we do with arrays; see
|
* next power of 2. This is similar to what we do with arrays; see
|
||||||
* JSObject::ensureDenseArrayElements.
|
* JSObject::ensureDenseArrayElements.
|
||||||
*/
|
*/
|
||||||
if (length > ROPE_DOUBLING_MAX)
|
static const size_t DOUBLING_MAX = 1024 * 1024;
|
||||||
return length + (length / 8);
|
numChars = numChars > DOUBLING_MAX ? numChars + (numChars / 8) : RoundUpPow2(numChars);
|
||||||
return RoundUpPow2(length);
|
|
||||||
}
|
/* Like length, capacity does not include the null char, so take it out. */
|
||||||
|
*capacity = numChars - 1;
|
||||||
|
|
||||||
static JS_ALWAYS_INLINE jschar *
|
|
||||||
AllocChars(JSContext *maybecx, size_t wholeCapacity)
|
|
||||||
{
|
|
||||||
/* +1 for the null char at the end. */
|
|
||||||
JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX);
|
JS_STATIC_ASSERT(JSString::MAX_LENGTH * sizeof(jschar) < UINT32_MAX);
|
||||||
size_t bytes = (wholeCapacity + 1) * sizeof(jschar);
|
size_t bytes = numChars * sizeof(jschar);
|
||||||
if (maybecx)
|
*chars = (jschar *)(maybecx ? maybecx->malloc_(bytes) : OffTheBooks::malloc_(bytes));
|
||||||
return (jschar *)maybecx->malloc_(bytes);
|
return *chars != NULL;
|
||||||
return (jschar *)OffTheBooks::malloc_(bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSFlatString *
|
JSFlatString *
|
||||||
|
@ -197,9 +198,7 @@ JSRope::flatten(JSContext *maybecx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wholeCapacity = RopeCapacityFor(wholeLength);
|
if (!AllocChars(maybecx, wholeLength, &wholeChars, &wholeCapacity))
|
||||||
wholeChars = AllocChars(maybecx, wholeCapacity);
|
|
||||||
if (!wholeChars)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pos = wholeChars;
|
pos = wholeChars;
|
||||||
|
|
|
@ -55,8 +55,11 @@ class JSAtom;
|
||||||
/*
|
/*
|
||||||
* JavaScript strings
|
* JavaScript strings
|
||||||
*
|
*
|
||||||
* Conceptually, a JS string is just an array of chars and a length. To improve
|
* Conceptually, a JS string is just an array of chars and a length. This array
|
||||||
* performance of common string operations, the following optimizations are
|
* of chars may or may not be null-terminated and, if it is, the null character
|
||||||
|
* is not included in the length.
|
||||||
|
*
|
||||||
|
* To improve performance of common operations, the following optimizations are
|
||||||
* made which affect the engine's representation of strings:
|
* made which affect the engine's representation of strings:
|
||||||
*
|
*
|
||||||
* - The plain vanilla representation is a "flat" string which consists of a
|
* - The plain vanilla representation is a "flat" string which consists of a
|
||||||
|
@ -110,7 +113,7 @@ class JSAtom;
|
||||||
* | \
|
* | \
|
||||||
* | JSDependentString base / -
|
* | JSDependentString base / -
|
||||||
* |
|
* |
|
||||||
* JSFlatString (abstract) chars / not null-terminated
|
* JSFlatString (abstract) chars / null-terminated
|
||||||
* | \
|
* | \
|
||||||
* | JSExtensibleString capacity / no external pointers into char array
|
* | JSExtensibleString capacity / no external pointers into char array
|
||||||
* |
|
* |
|
||||||
|
|
|
@ -842,8 +842,7 @@ RasterImage::InternalAddFrame(PRUint32 framenum,
|
||||||
|
|
||||||
if (mFrames.Length() == 1) {
|
if (mFrames.Length() == 1) {
|
||||||
// Since we're about to add our second frame, initialize animation stuff
|
// Since we're about to add our second frame, initialize animation stuff
|
||||||
if (!ensureAnimExists())
|
EnsureAnimExists();
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
// If we dispose of the first frame by clearing it, then the
|
// If we dispose of the first frame by clearing it, then the
|
||||||
// First Frame's refresh area is all of itself.
|
// First Frame's refresh area is all of itself.
|
||||||
|
@ -1113,8 +1112,7 @@ RasterImage::StartAnimation()
|
||||||
|
|
||||||
NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
|
NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
|
||||||
|
|
||||||
if (!ensureAnimExists())
|
EnsureAnimExists();
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
NS_ABORT_IF_FALSE(mAnim && !mAnim->timer, "Anim must exist and not have a timer yet");
|
NS_ABORT_IF_FALSE(mAnim && !mAnim->timer, "Anim must exist and not have a timer yet");
|
||||||
|
|
||||||
|
|
|
@ -382,7 +382,7 @@ private:
|
||||||
imgFrame* GetCurrentDrawableImgFrame();
|
imgFrame* GetCurrentDrawableImgFrame();
|
||||||
PRUint32 GetCurrentImgFrameIndex() const;
|
PRUint32 GetCurrentImgFrameIndex() const;
|
||||||
|
|
||||||
inline Anim* ensureAnimExists()
|
inline void EnsureAnimExists()
|
||||||
{
|
{
|
||||||
if (!mAnim) {
|
if (!mAnim) {
|
||||||
|
|
||||||
|
@ -400,7 +400,6 @@ private:
|
||||||
// is acceptable for the moment.
|
// is acceptable for the moment.
|
||||||
LockImage();
|
LockImage();
|
||||||
}
|
}
|
||||||
return mAnim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Function for doing the frame compositing of animations
|
/** Function for doing the frame compositing of animations
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
#include "dynamic_images.h"
|
#include "dynamic_images.h"
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
|
||||||
#define HAS_PPC_SUPPORT
|
#define HAS_PPC_SUPPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче