diff --git a/content/html/content/public/nsHTMLMediaElement.h b/content/html/content/public/nsHTMLMediaElement.h index 1b2694ac9af..45d31997e0b 100644 --- a/content/html/content/public/nsHTMLMediaElement.h +++ b/content/html/content/public/nsHTMLMediaElement.h @@ -50,6 +50,7 @@ #include "nsIObserver.h" #include "ImageLayers.h" #include "nsAudioStream.h" +#include "nsTimeRanges.h" // Define to output information on decoding and painting framerate /* #define DEBUG_FRAME_RATE 1 */ @@ -624,6 +625,12 @@ protected: // a media and element same-origin check. 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. // Set to false when completed, or not yet started. PRPackedBool mBegun; diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 7e57f3f8e1e..3ca71f0a0ed 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -39,7 +39,6 @@ #include "nsIDOMHTMLMediaElement.h" #include "nsIDOMHTMLSourceElement.h" #include "nsHTMLMediaElement.h" -#include "nsTimeRanges.h" #include "nsGenericHTMLElement.h" #include "nsPresContext.h" #include "nsIPresShell.h" @@ -1092,6 +1091,16 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(double aCurrentTime) { 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) { LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) failed: no decoder", this, aCurrentTime)); 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)); 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 AddRemoveSelfReference(); @@ -1142,6 +1154,35 @@ NS_IMETHODIMP nsHTMLMediaElement::GetPaused(PRBool *aPaused) return NS_OK; } +/* readonly attribute nsIDOMHTMLTimeRanges played; */ +NS_IMETHODIMP nsHTMLMediaElement::GetPlayed(nsIDOMTimeRanges** aPlayed) +{ + nsRefPtr 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 (); */ NS_IMETHODIMP nsHTMLMediaElement::Pause() { @@ -1280,6 +1321,7 @@ nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed aNodeInfo, mMediaSize(-1,-1), mLastCurrentTime(0.0), mAllowAudioData(PR_FALSE), + mCurrentPlayRangeStart(-1.0), mBegun(PR_FALSE), mLoadedFirstFrame(PR_FALSE), 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 // seek to the effective start. // 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 AddRemoveSelfReference(); + double end = 0.0; + GetCurrentTime(&end); + if (mCurrentPlayRangeStart != end) { + mPlayed.Add(mCurrentPlayRangeStart, end); + } + mCurrentPlayRangeStart = -1.0; + if (mDecoder && mDecoder->IsInfinite()) { LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the stream", this)); DispatchAsyncEvent(NS_LITERAL_STRING("durationchange")); @@ -2455,7 +2508,7 @@ void nsHTMLMediaElement::NotifyAddedSource() } // 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) { QueueLoadFromSourceTask(); } diff --git a/content/html/content/src/nsTimeRanges.cpp b/content/html/content/src/nsTimeRanges.cpp index 70c3e1889f1..90367f53a7f 100644 --- a/content/html/content/src/nsTimeRanges.cpp +++ b/content/html/content/src/nsTimeRanges.cpp @@ -85,3 +85,28 @@ void nsTimeRanges::Add(double aStart, double aEnd) { mRanges.AppendElement(TimeRange(aStart,aEnd)); } + +void +nsTimeRanges::Normalize() { + if (mRanges.Length() <= 1) { + return; + } + nsAutoTArray 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; +} diff --git a/content/html/content/src/nsTimeRanges.h b/content/html/content/src/nsTimeRanges.h index 172cadb5b85..59678a0a4e7 100644 --- a/content/html/content/src/nsTimeRanges.h +++ b/content/html/content/src/nsTimeRanges.h @@ -55,6 +55,9 @@ public: void Add(double aStart, double aEnd); + // See . + void Normalize(); + private: struct TimeRange { @@ -65,6 +68,21 @@ private: 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 mRanges; }; diff --git a/content/media/test/Makefile.in b/content/media/test/Makefile.in index a538b7550a0..b26441e1387 100644 --- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -126,6 +126,7 @@ _TEST_FILES = \ test_paused_after_ended.html \ test_play_events.html \ test_play_events_2.html \ + test_played.html \ test_playback.html \ test_playback_errors.html \ test_preload_actions.html \ diff --git a/content/media/test/manifest.js b/content/media/test/manifest.js index 7ef33b9fa77..763d16a798d 100644 --- a/content/media/test/manifest.js +++ b/content/media/test/manifest.js @@ -23,6 +23,14 @@ var gProgressTests = [ { 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 // anything for testing clone-specific bugs. var gCloneTests = gSmallTests.concat([ diff --git a/content/media/test/test_played.html b/content/media/test/test_played.html new file mode 100644 index 00000000000..9c298b35ed6 --- /dev/null +++ b/content/media/test/test_played.html @@ -0,0 +1,233 @@ + + + +Test played member for media elements + + + + + + +
+
+
+ + diff --git a/dom/interfaces/html/nsIDOMHTMLAudioElement.idl b/dom/interfaces/html/nsIDOMHTMLAudioElement.idl index a0f44339e58..6c4805d081f 100644 --- a/dom/interfaces/html/nsIDOMHTMLAudioElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLAudioElement.idl @@ -52,7 +52,7 @@ * @status UNDER_DEVELOPMENT */ -[scriptable, uuid(f0d4977c-9632-4fab-bc9b-91c250a6ef96)] +[scriptable, uuid(1f2437f1-6037-40c4-bfb6-105c6c60f0ca)] interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement { // Setup the audio stream for writing diff --git a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl index dcbcad76c3a..8181aeb768c 100644 --- a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLMediaElement.idl @@ -57,7 +57,7 @@ #endif %} -[scriptable, uuid(d8213322-46d8-47ca-a15c-2abae47ddfde)] +[scriptable, uuid(c8a5f714-97de-4e2c-8394-2397870224bb)] interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement { // error state @@ -89,6 +89,7 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement attribute double currentTime; readonly attribute double duration; readonly attribute boolean paused; + readonly attribute nsIDOMTimeRanges played; readonly attribute boolean ended; readonly attribute boolean mozAutoplayEnabled; attribute boolean autoplay; diff --git a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl b/dom/interfaces/html/nsIDOMHTMLVideoElement.idl index ac0f5d07e79..d4b0fe60b06 100644 --- a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLVideoElement.idl @@ -48,15 +48,15 @@ * @status UNDER_DEVELOPMENT */ -[scriptable, uuid(00c757ec-db7b-477e-95cd-b2a03b0f8634)] +[scriptable, uuid(169f0ff1-511a-453d-86b6-346c1e936122)] interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement { - attribute long width; + attribute long width; attribute long height; readonly attribute unsigned long videoWidth; readonly attribute unsigned long videoHeight; attribute DOMString poster; - + // 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 // frames. diff --git a/js/src/jit-test/tests/basic/testBug663789-2.js b/js/src/jit-test/tests/basic/testBug663789-2.js index 46311648842..d7ee3059986 100644 --- a/js/src/jit-test/tests/basic/testBug663789-2.js +++ b/js/src/jit-test/tests/basic/testBug663789-2.js @@ -1,11 +1,6 @@ // |jit-test| debug;mjit -/* - * NOTE: this evalInFrame is explicitly exposing an optimization artifact that - * 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") } } +o = { toString:function() { return evalInFrame(1, "x") } } +var x = 'C'; var s = "aaaaaaaaaa".replace(/a/g, function() { var x = 'B'; return o }); -assertEq(s, "BBBBBBBBBB"); +assertEq(s, "CCCCCCCCCC"); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 5e692174238..dc603bb742c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4473,7 +4473,7 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, JSPrincipals *p if (script) { scriptObj = js_NewScriptObject(cx, script); if (!scriptObj) - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 3); } LAST_FRAME_CHECKS(cx, scriptObj); return scriptObj; @@ -4660,7 +4660,7 @@ CompileFileHelper(JSContext *cx, JSObject *obj, JSPrincipals *principals, JSObject *scriptObj = js_NewScriptObject(cx, script); if (!scriptObj) - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 4); return scriptObj; } @@ -4967,7 +4967,7 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj, bool ok = ExternalExecute(cx, script, *obj, Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 5); return ok; } diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index deb983832a7..4d8a1fdddd5 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -1125,7 +1125,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg, bool ok = Execute(cx, script, *scobj, fp->thisValue(), EXECUTE_DEBUG, fp, Valueify(rval)); - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 6); return ok; } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index baac27d2a4b..50495327dab 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1586,8 +1586,14 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) 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; + fun->u.i.script = script; if (xdr->mode == JSXDR_DECODE) { *objp = FUN_OBJECT(fun); @@ -2474,9 +2480,10 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, JS_ASSERT(script->compartment != cx->compartment); JS_OPT_ASSERT(script->ownerObject == fun); - cfun->u.i.script = js_CloneScript(cx, script); - if (!cfun->script()) + JSScript *cscript = js_CloneScript(cx, script); + if (!cscript) return NULL; + cfun->u.i.script = cscript; cfun->script()->setOwnerObject(cfun); #ifdef CHECK_SCRIPT_OWNER cfun->script()->owner = NULL; diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index face6685480..fdef86e682a 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -709,6 +709,9 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this savedCallee_ = args_.calleev() = calleev; savedThis_ = args_.thisv() = thisv; + /* If anyone (through jsdbgapi) finds this frame, make it safe. */ + MakeRangeGCSafe(args_.argv(), args_.argc()); + do { /* Hoist dynamic checks from scripted Invoke. */ if (!calleev.isObject()) diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index aba95a8d5da..9c87e9e2208 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -1142,7 +1142,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF late_error: if (script) { - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 7); script = NULL; } goto out; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 28a6865636b..528f1c754d4 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -754,7 +754,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp) error: if (xdr->mode == JSXDR_DECODE) { - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 1); *scriptp = NULL; } xdr->script = oldscript; @@ -1270,7 +1270,7 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) return script; bad: - js_DestroyScript(cx, script); + js_DestroyScript(cx, script, 2); return NULL; } @@ -1345,7 +1345,7 @@ CheckCompartmentScripts(JSCompartment *comp) } /* namespace js */ static void -DestroyScript(JSContext *cx, JSScript *script, JSObject *owner) +DestroyScript(JSContext *cx, JSScript *script, JSObject *owner, uint32 caller) { CheckScript(script, NULL); CheckScriptOwner(script, owner); @@ -1408,16 +1408,17 @@ DestroyScript(JSContext *cx, JSScript *script, JSObject *owner) if (script->sourceMap) cx->free_(script->sourceMap); - memset(script, JS_FREE_PATTERN, script->totalSize()); + memset(script, 0xdb, script->totalSize()); + *(uint32 *)script = caller; cx->free_(script); } void -js_DestroyScript(JSContext *cx, JSScript *script) +js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller) { JS_ASSERT(!cx->runtime->gcRunning); js_CallDestroyScriptHook(cx, script); - DestroyScript(cx, script, JS_NEW_SCRIPT); + DestroyScript(cx, script, JS_NEW_SCRIPT, caller); } void @@ -1425,14 +1426,14 @@ js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner) { JS_ASSERT(cx->runtime->gcRunning); js_CallDestroyScriptHook(cx, script); - DestroyScript(cx, script, owner); + DestroyScript(cx, script, owner, 100); } void js_DestroyCachedScript(JSContext *cx, JSScript *script) { JS_ASSERT(cx->runtime->gcRunning); - DestroyScript(cx, script, JS_CACHED_SCRIPT); + DestroyScript(cx, script, JS_CACHED_SCRIPT, 101); } void diff --git a/js/src/jsscript.h b/js/src/jsscript.h index d27b42c46b7..f0cad899a9c 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -733,7 +733,7 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script); * only on the current thread. */ extern void -js_DestroyScript(JSContext *cx, JSScript *script); +js_DestroyScript(JSContext *cx, JSScript *script, uint32 caller); extern void js_DestroyScriptFromGC(JSContext *cx, JSScript *script, JSObject *owner); diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index bf1aee66b73..35a4c8463f6 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -70,19 +70,26 @@ JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)())); static JS_NEVER_INLINE void 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) /* * We used to call DebugBreak() on Windows, but amazingly, it causes * the MSVS 2010 debugger not to be able to recover a call stack. */ - *((int *) NULL) = 0; + *((int *) NULL) = 123; exit(3); #elif defined(__APPLE__) /* * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are * 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. */ #else raise(SIGABRT); /* To continue from here in GDB: "signal 0". */ diff --git a/js/src/jsxdrapi.cpp b/js/src/jsxdrapi.cpp index ce38636c1f4..8585ca0fe9c 100644 --- a/js/src/jsxdrapi.cpp +++ b/js/src/jsxdrapi.cpp @@ -720,7 +720,7 @@ JS_XDRScriptObject(JSXDRState *xdr, JSObject **scriptObjp) js_CallNewScriptHook(xdr->cx, script, NULL); *scriptObjp = js_NewScriptObject(xdr->cx, script); if (!*scriptObjp) { - js_DestroyScript(xdr->cx, script); + js_DestroyScript(xdr->cx, script, 8); return false; } } diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index def187658b5..24d14ee9922 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -963,6 +963,12 @@ StackIter::settleOnNewState() 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 * natives called directly by a script (compiled or interpreted). diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 5eb6da56221..dc34c5060e0 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -116,30 +116,31 @@ JSString::charsHeapSize() return length() * sizeof(jschar); } -static JS_ALWAYS_INLINE size_t -RopeCapacityFor(size_t length) +static JS_ALWAYS_INLINE bool +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 * next power of 2. This is similar to what we do with arrays; see * JSObject::ensureDenseArrayElements. */ - if (length > ROPE_DOUBLING_MAX) - return length + (length / 8); - return RoundUpPow2(length); -} + static const size_t DOUBLING_MAX = 1024 * 1024; + numChars = numChars > DOUBLING_MAX ? numChars + (numChars / 8) : RoundUpPow2(numChars); + + /* 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); - size_t bytes = (wholeCapacity + 1) * sizeof(jschar); - if (maybecx) - return (jschar *)maybecx->malloc_(bytes); - return (jschar *)OffTheBooks::malloc_(bytes); + size_t bytes = numChars * sizeof(jschar); + *chars = (jschar *)(maybecx ? maybecx->malloc_(bytes) : OffTheBooks::malloc_(bytes)); + return *chars != NULL; } JSFlatString * @@ -197,9 +198,7 @@ JSRope::flatten(JSContext *maybecx) } } - wholeCapacity = RopeCapacityFor(wholeLength); - wholeChars = AllocChars(maybecx, wholeCapacity); - if (!wholeChars) + if (!AllocChars(maybecx, wholeLength, &wholeChars, &wholeCapacity)) return NULL; pos = wholeChars; diff --git a/js/src/vm/String.h b/js/src/vm/String.h index c47f89e38c3..2bbffebe908 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -55,8 +55,11 @@ class JSAtom; /* * JavaScript strings * - * Conceptually, a JS string is just an array of chars and a length. To improve - * performance of common string operations, the following optimizations are + * Conceptually, a JS string is just an array of chars and a length. This array + * 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: * * - The plain vanilla representation is a "flat" string which consists of a @@ -110,7 +113,7 @@ class JSAtom; * | \ * | JSDependentString base / - * | - * JSFlatString (abstract) chars / not null-terminated + * JSFlatString (abstract) chars / null-terminated * | \ * | JSExtensibleString capacity / no external pointers into char array * | diff --git a/modules/libpr0n/src/RasterImage.cpp b/modules/libpr0n/src/RasterImage.cpp index e86e7fbf935..6500a736a87 100644 --- a/modules/libpr0n/src/RasterImage.cpp +++ b/modules/libpr0n/src/RasterImage.cpp @@ -842,8 +842,7 @@ RasterImage::InternalAddFrame(PRUint32 framenum, if (mFrames.Length() == 1) { // Since we're about to add our second frame, initialize animation stuff - if (!ensureAnimExists()) - return NS_ERROR_OUT_OF_MEMORY; + EnsureAnimExists(); // If we dispose of the first frame by clearing it, then the // First Frame's refresh area is all of itself. @@ -1113,8 +1112,7 @@ RasterImage::StartAnimation() NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!"); - if (!ensureAnimExists()) - return NS_ERROR_OUT_OF_MEMORY; + EnsureAnimExists(); NS_ABORT_IF_FALSE(mAnim && !mAnim->timer, "Anim must exist and not have a timer yet"); diff --git a/modules/libpr0n/src/RasterImage.h b/modules/libpr0n/src/RasterImage.h index bb2208f49e2..5d1f0009dda 100644 --- a/modules/libpr0n/src/RasterImage.h +++ b/modules/libpr0n/src/RasterImage.h @@ -382,7 +382,7 @@ private: imgFrame* GetCurrentDrawableImgFrame(); PRUint32 GetCurrentImgFrameIndex() const; - inline Anim* ensureAnimExists() + inline void EnsureAnimExists() { if (!mAnim) { @@ -400,7 +400,6 @@ private: // is acceptable for the moment. LockImage(); } - return mAnim; } /** Function for doing the frame compositing of animations diff --git a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h index 55c4c8a3468..1228b977b33 100644 --- a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h +++ b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h @@ -43,7 +43,7 @@ #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 #endif