From 268c158f7d00d2ab1cf76bee99f7ebb3786e3d9b Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Mon, 9 Jun 2014 09:03:35 +0200 Subject: [PATCH 01/52] Bug 906632 - Indentation size in gcli's JavaScript beautifier should follow devtools.editor.tabsize. r=mratcliffe --- toolkit/devtools/gcli/commands/jsb.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/toolkit/devtools/gcli/commands/jsb.js b/toolkit/devtools/gcli/commands/jsb.js index de3ec61af9af..b110aa35a662 100644 --- a/toolkit/devtools/gcli/commands/jsb.js +++ b/toolkit/devtools/gcli/commands/jsb.js @@ -8,6 +8,7 @@ const { Cc, Ci, Cu } = require("chrome"); const gcli = require("gcli/index"); const XMLHttpRequest = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]; +loader.lazyImporter(this, "Preferences", "resource://gre/modules/Preferences.jsm"); loader.lazyImporter(this, "js_beautify", "resource:///modules/devtools/Jsbeautify.jsm"); exports.items = [ @@ -29,7 +30,7 @@ exports.items = [ type: "number", description: gcli.lookup("jsbIndentSizeDesc"), manual: gcli.lookup("jsbIndentSizeManual"), - defaultValue: 2 + defaultValue: Preferences.get("devtools.editor.tabsize", 2), }, { name: "indentChar", From 2bc6ebbf63412b9e7b3b718209b924cdd068abe9 Mon Sep 17 00:00:00 2001 From: Hernan Rodriguez Colmeiro Date: Fri, 23 May 2014 08:21:00 -0400 Subject: [PATCH 02/52] Bug 1007881 - Dropdown is too narrow in the in-content preferences. r=jaws --- browser/themes/osx/preferences/in-content/preferences.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/browser/themes/osx/preferences/in-content/preferences.css b/browser/themes/osx/preferences/in-content/preferences.css index f4550c89355a..0fddc85e50a3 100644 --- a/browser/themes/osx/preferences/in-content/preferences.css +++ b/browser/themes/osx/preferences/in-content/preferences.css @@ -29,6 +29,13 @@ menulist:not([editable="true"]) > .menulist-dropmarker { margin-bottom: 1px; } +menulist > menupopup menu, +menulist > menupopup menuitem, +button[type="menu"] > menupopup menu, +button[type="menu"] > menupopup menuitem { + -moz-padding-end: 34px; +} + .help-button > .button-box > .button-icon { -moz-margin-start: 0; } From e70c19ec8cb80c5d7e81162c23ad2788c59b03d9 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 9 Jun 2014 09:44:30 -0700 Subject: [PATCH 03/52] Bug 1021001 - Remove AutoCheckCannotGC from NamespaceImports.h, and require users to use the sole definition in GCAPI.h. r=terrence --- js/src/NamespaceImports.h | 4 ---- js/src/jit/ParallelFunctions.cpp | 2 ++ js/src/jsarray.cpp | 2 ++ js/src/jsinferinlines.h | 2 +- js/src/jsnum.cpp | 2 ++ js/src/jsopcode.cpp | 2 ++ js/src/jsstr.cpp | 2 ++ js/src/vm/SelfHosting.cpp | 2 ++ js/src/vm/String-inl.h | 2 +- js/src/vm/String.cpp | 2 ++ js/src/vm/TypedArrayObject.h | 2 +- 11 files changed, 17 insertions(+), 7 deletions(-) diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index 6fe6c51a9b10..32ffe001bbc6 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -42,8 +42,6 @@ class MOZ_STACK_CLASS SourceBufferHolder; class HandleValueArray; -class AutoCheckCannotGC; - } // Do the importing. @@ -135,8 +133,6 @@ using JS::HandleValueArray; using JS::Zone; -using JS::AutoCheckCannotGC; - } /* namespace js */ #endif /* NamespaceImports_h */ diff --git a/js/src/jit/ParallelFunctions.cpp b/js/src/jit/ParallelFunctions.cpp index e28200357000..130b73809746 100644 --- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -17,6 +17,8 @@ using namespace js; using namespace jit; +using JS::AutoCheckCannotGC; + using parallel::Spew; using parallel::SpewOps; using parallel::SpewBailouts; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 257e2b462d22..c863485dd0be 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -49,6 +49,8 @@ using mozilla::DebugOnly; using mozilla::IsNaN; using mozilla::PointerRangeSize; +using JS::AutoCheckCannotGC; + bool js::GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp) { diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index b3791f802f67..e017b655fb28 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -203,7 +203,7 @@ IdToTypeId(jsid id) if (JSID_IS_STRING(id)) { JSAtom *atom = JSID_TO_ATOM(id); - AutoCheckCannotGC nogc; + JS::AutoCheckCannotGC nogc; bool isNumeric = atom->hasLatin1Chars() ? IdIsNumericTypeId(atom->latin1Range(nogc)) : IdIsNumericTypeId(atom->twoByteRange(nogc)); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index d801d715cff7..9ce6d7bd2f7b 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -46,6 +46,8 @@ using mozilla::NegativeInfinity; using mozilla::PodCopy; using mozilla::PositiveInfinity; using mozilla::RangedPtr; + +using JS::AutoCheckCannotGC; using JS::GenericNaN; /* diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 71be550b896d..008b354a4664 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -45,6 +45,8 @@ using namespace js; using namespace js::gc; +using JS::AutoCheckCannotGC; + using js::frontend::IsIdentifier; /* diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index b23337be8a81..f031d66bff65 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -73,6 +73,8 @@ using mozilla::PodCopy; using mozilla::PodEqual; using mozilla::SafeCast; +using JS::AutoCheckCannotGC; + typedef Handle HandleLinearString; static JSLinearString * diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index df64955997c8..c6a0c95aa09a 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -33,6 +33,8 @@ using namespace js; using namespace js::selfhosted; +using JS::AutoCheckCannotGC; + static void selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 48078a937ad9..0cf39f30c877 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -88,7 +88,7 @@ NewFatInlineString(ExclusiveContext *cx, Handle base, size_t st if (!s) return nullptr; - AutoCheckCannotGC nogc; + JS::AutoCheckCannotGC nogc; mozilla::PodCopy(chars, base->chars(nogc) + start, length); chars[length] = 0; return s; diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 9f32a17cd345..26431728c70e 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -24,6 +24,8 @@ using mozilla::PodCopy; using mozilla::RangedPtr; using mozilla::RoundUpPow2; +using JS::AutoCheckCannotGC; + size_t JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) { diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index ac02085d3d2b..5dcaefff4b05 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -188,7 +188,7 @@ IsTypedArrayIndex(jsid id, uint64_t *indexp) if (MOZ_UNLIKELY(!JSID_IS_STRING(id))) return false; - AutoCheckCannotGC nogc; + JS::AutoCheckCannotGC nogc; JSAtom *atom = JSID_TO_ATOM(id); size_t length = atom->length(); From 4b58129b33569c41e58240221934cad9f417dd42 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 9 Jun 2014 10:35:59 -0700 Subject: [PATCH 04/52] Bug 1022784 - Make all users of AutoGCRooter depend upon its definition, not upon forward declarations of it. r=terrence --- js/src/NamespaceImports.h | 2 - js/src/builtin/MapObject.h | 6 +-- js/src/frontend/BytecodeCompiler.h | 2 +- js/src/frontend/Parser.cpp | 3 ++ js/src/frontend/Parser.h | 4 +- js/src/gc/RootMarking.cpp | 6 ++- js/src/jit/IonAllocPolicy.h | 6 +-- js/src/jit/IonMacroAssembler.h | 4 +- js/src/jsapi.cpp | 2 + js/src/jsapi.h | 60 -------------------------- js/src/jscntxt.h | 6 +-- js/src/jscompartment.h | 6 +-- js/src/jsgc.cpp | 2 + js/src/jsonparser.h | 4 +- js/src/jspubtd.h | 69 +++++++++++++++++++++++++++++- 15 files changed, 98 insertions(+), 84 deletions(-) diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index 32ffe001bbc6..5be3056595ca 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -32,7 +32,6 @@ class AutoValueVector; class AutoIdArray; -class JS_PUBLIC_API(AutoGCRooter); template class AutoVectorRooter; template class AutoHashMapRooter; template class AutoHashSetRooter; @@ -78,7 +77,6 @@ using JS::AutoValueVector; using JS::AutoIdArray; -using JS::AutoGCRooter; using JS::AutoHashMapRooter; using JS::AutoHashSetRooter; using JS::AutoVectorRooter; diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index 1c5a15dc5b1c..930c88373dd3 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -42,12 +42,12 @@ class HashableValue { Value get() const { return value.get(); } }; -class AutoHashableValueRooter : private AutoGCRooter +class AutoHashableValueRooter : private JS::AutoGCRooter { public: explicit AutoHashableValueRooter(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, HASHABLEVALUE) + : JS::AutoGCRooter(cx, HASHABLEVALUE) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } @@ -62,7 +62,7 @@ class AutoHashableValueRooter : private AutoGCRooter Value get() const { return value.get(); } - friend void AutoGCRooter::trace(JSTracer *trc); + friend void JS::AutoGCRooter::trace(JSTracer *trc); void trace(JSTracer *trc); private: diff --git a/js/src/frontend/BytecodeCompiler.h b/js/src/frontend/BytecodeCompiler.h index e236b68ebd21..9156a7bd57d8 100644 --- a/js/src/frontend/BytecodeCompiler.h +++ b/js/src/frontend/BytecodeCompiler.h @@ -68,7 +68,7 @@ IsKeyword(JSLinearString *str); /* GC marking. Defined in Parser.cpp. */ void -MarkParser(JSTracer *trc, AutoGCRooter *parser); +MarkParser(JSTracer *trc, JS::AutoGCRooter *parser); } /* namespace frontend */ } /* namespace js */ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index d71fe6502f7f..62f811788d1d 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -42,8 +42,11 @@ using namespace js; using namespace js::gc; + using mozilla::Maybe; +using JS::AutoGCRooter; + namespace js { namespace frontend { diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 05fc9c89ca8c..ebc9930157ec 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -313,7 +313,7 @@ enum VarContext { HoistVars, DontHoistVars }; enum FunctionType { Getter, Setter, Normal }; template -class Parser : private AutoGCRooter, public StrictModeGetter +class Parser : private JS::AutoGCRooter, public StrictModeGetter { public: ExclusiveContext *const context; @@ -392,7 +392,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter traceListHead = m.traceListHead; } - friend void js::frontend::MarkParser(JSTracer *trc, AutoGCRooter *parser); + friend void js::frontend::MarkParser(JSTracer *trc, JS::AutoGCRooter *parser); const char *getFilename() const { return tokenStream.getFilename(); } JSVersion versionNumber() const { return tokenStream.versionNumber(); } diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 3abe077e76f8..b877b5fdb09d 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -36,6 +36,8 @@ using namespace js::gc; using mozilla::ArrayEnd; +using JS::AutoGCRooter; + typedef RootedValueMap::Range RootRange; typedef RootedValueMap::Entry RootEntry; typedef RootedValueMap::Enum RootEnum; @@ -582,7 +584,7 @@ AutoGCRooter::trace(JSTracer *trc) AutoGCRooter::traceAll(JSTracer *trc) { for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) { - for (js::AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) + for (AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) gcr->trace(trc); } } @@ -591,7 +593,7 @@ AutoGCRooter::traceAll(JSTracer *trc) AutoGCRooter::traceAllWrappers(JSTracer *trc) { for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) { - for (js::AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) { + for (AutoGCRooter *gcr = cx->autoGCRooters; gcr; gcr = gcr->down) { if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER) gcr->trace(trc); } diff --git a/js/src/jit/IonAllocPolicy.h b/js/src/jit/IonAllocPolicy.h index 1c9ed9045998..d1e0f319e3ac 100644 --- a/js/src/jit/IonAllocPolicy.h +++ b/js/src/jit/IonAllocPolicy.h @@ -74,17 +74,17 @@ class TempAllocator }; // Stack allocated rooter for all roots associated with a TempAllocator -class AutoTempAllocatorRooter : private AutoGCRooter +class AutoTempAllocatorRooter : private JS::AutoGCRooter { public: explicit AutoTempAllocatorRooter(JSContext *cx, TempAllocator *temp MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, IONALLOC), temp(temp) + : JS::AutoGCRooter(cx, IONALLOC), temp(temp) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } - friend void AutoGCRooter::trace(JSTracer *trc); + friend void JS::AutoGCRooter::trace(JSTracer *trc); void trace(JSTracer *trc); private: diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 01723e54f069..95df122f6153 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -41,13 +41,13 @@ class MacroAssembler : public MacroAssemblerSpecific } public: - class AutoRooter : public AutoGCRooter + class AutoRooter : public JS::AutoGCRooter { MacroAssembler *masm_; public: AutoRooter(JSContext *cx, MacroAssembler *masm) - : AutoGCRooter(cx, IONMASM), + : JS::AutoGCRooter(cx, IONMASM), masm_(masm) { } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index ab4dace986f9..c4117b822270 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -98,6 +98,8 @@ using mozilla::Maybe; using mozilla::PodCopy; using mozilla::PodZero; +using JS::AutoGCRooter; + using js::frontend::Parser; #ifdef HAVE_VA_LIST_AS_ARRAY diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 6f8dd7933f92..d7dacf46989f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -74,66 +74,6 @@ inline void AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v) { } #endif /* JS_DEBUG */ -class JS_PUBLIC_API(AutoGCRooter) { - public: - AutoGCRooter(JSContext *cx, ptrdiff_t tag); - AutoGCRooter(js::ContextFriendFields *cx, ptrdiff_t tag); - - ~AutoGCRooter() { - JS_ASSERT(this == *stackTop); - *stackTop = down; - } - - /* Implemented in gc/RootMarking.cpp. */ - inline void trace(JSTracer *trc); - static void traceAll(JSTracer *trc); - static void traceAllWrappers(JSTracer *trc); - - protected: - AutoGCRooter * const down; - - /* - * Discriminates actual subclass of this being used. If non-negative, the - * subclass roots an array of values of the length stored in this field. - * If negative, meaning is indicated by the corresponding value in the enum - * below. Any other negative value indicates some deeper problem such as - * memory corruption. - */ - ptrdiff_t tag_; - - enum { - VALARRAY = -2, /* js::AutoValueArray */ - PARSER = -3, /* js::frontend::Parser */ - SHAPEVECTOR = -4, /* js::AutoShapeVector */ - IDARRAY = -6, /* js::AutoIdArray */ - DESCVECTOR = -7, /* js::AutoPropDescVector */ - VALVECTOR = -10, /* js::AutoValueVector */ - IDVECTOR = -13, /* js::AutoIdVector */ - OBJVECTOR = -14, /* js::AutoObjectVector */ - STRINGVECTOR =-15, /* js::AutoStringVector */ - SCRIPTVECTOR =-16, /* js::AutoScriptVector */ - NAMEVECTOR = -17, /* js::AutoNameVector */ - HASHABLEVALUE=-18, /* js::HashableValue */ - IONMASM = -19, /* js::jit::MacroAssembler */ - IONALLOC = -20, /* js::jit::AutoTempAllocatorRooter */ - WRAPVECTOR = -21, /* js::AutoWrapperVector */ - WRAPPER = -22, /* js::AutoWrapperRooter */ - OBJOBJHASHMAP=-23, /* js::AutoObjectObjectHashMap */ - OBJU32HASHMAP=-24, /* js::AutoObjectUnsigned32HashMap */ - OBJHASHSET = -25, /* js::AutoObjectHashSet */ - JSONPARSER = -26, /* js::JSONParser */ - CUSTOM = -27, /* js::CustomAutoRooter */ - FUNVECTOR = -28 /* js::AutoFunctionVector */ - }; - - private: - AutoGCRooter ** const stackTop; - - /* No copy or assignment semantics. */ - AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE; - void operator=(AutoGCRooter &ida) MOZ_DELETE; -}; - /* AutoValueArray roots an internal fixed-size array of Values. */ template class AutoValueArray : public AutoGCRooter diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index aeda6640be7f..0e3aa8416230 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -914,12 +914,12 @@ class AutoObjectHashSet : public AutoHashSetRooter }; /* AutoArrayRooter roots an external array of Values. */ -class AutoArrayRooter : private AutoGCRooter +class AutoArrayRooter : private JS::AutoGCRooter { public: AutoArrayRooter(JSContext *cx, size_t len, Value *vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, len), array(vec) + : JS::AutoGCRooter(cx, len), array(vec) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(tag_ >= 0); @@ -961,7 +961,7 @@ class AutoArrayRooter : private AutoGCRooter return HandleValue::fromMarkedLocation(&array[i]); } - friend void AutoGCRooter::trace(JSTracer *trc); + friend void JS::AutoGCRooter::trace(JSTracer *trc); private: Value *array; diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 169e353a2a2c..a99325cd5395 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -656,11 +656,11 @@ class AutoWrapperVector : public AutoVectorRooter MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -class AutoWrapperRooter : private AutoGCRooter { +class AutoWrapperRooter : private JS::AutoGCRooter { public: AutoWrapperRooter(JSContext *cx, WrapperValue v MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, WRAPPER), value(v) + : JS::AutoGCRooter(cx, WRAPPER), value(v) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } @@ -669,7 +669,7 @@ class AutoWrapperRooter : private AutoGCRooter { return value.get().toObjectOrNull(); } - friend void AutoGCRooter::trace(JSTracer *trc); + friend void JS::AutoGCRooter::trace(JSTracer *trc); private: WrapperValue value; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 54ede726b466..9c7e37752f97 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -230,6 +230,8 @@ using mozilla::DebugOnly; using mozilla::Maybe; using mozilla::Swap; +using JS::AutoGCRooter; + /* Perform a Full GC every 20 seconds if MaybeGC is called */ static const uint64_t GC_IDLE_FULL_SPAN = 20 * 1000 * 1000; diff --git a/js/src/jsonparser.h b/js/src/jsonparser.h index 48bfc4906720..2cd50299ee94 100644 --- a/js/src/jsonparser.h +++ b/js/src/jsonparser.h @@ -9,12 +9,14 @@ #include "mozilla/Attributes.h" +#include "jspubtd.h" + #include "ds/IdValuePair.h" #include "vm/String.h" namespace js { -class MOZ_STACK_CLASS JSONParser : private AutoGCRooter +class MOZ_STACK_CLASS JSONParser : private JS::AutoGCRooter { public: enum ErrorHandling { RaiseError, NoError }; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 8d7b986c300b..1e16c5d37e9a 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -11,6 +11,7 @@ * JS public API typedefs. */ +#include "mozilla/Assertions.h" #include "mozilla/LinkedList.h" #include "mozilla/NullPtr.h" #include "mozilla/PodOperations.h" @@ -32,8 +33,6 @@ class CallArgs; template class Rooted; -class JS_PUBLIC_API(AutoGCRooter); - class JS_FRIEND_API(CompileOptions); class JS_FRIEND_API(ReadOnlyCompileOptions); class JS_FRIEND_API(OwningCompileOptions); @@ -43,6 +42,10 @@ struct Zone; } /* namespace JS */ +namespace js { +struct ContextFriendFields; +} // namespace js + /* * Run-time version enumeration. For compile-time version checking, please use * the JS_HAS_* macros in jsversion.h, or use MOZJS_MAJOR_VERSION, @@ -246,6 +249,68 @@ inline mozilla::LinkedList &Runtime::getPersistentRootedList() { return valuePersistentRooteds; } } /* namespace shadow */ + +class JS_PUBLIC_API(AutoGCRooter) +{ + public: + AutoGCRooter(JSContext *cx, ptrdiff_t tag); + AutoGCRooter(js::ContextFriendFields *cx, ptrdiff_t tag); + + ~AutoGCRooter() { + MOZ_ASSERT(this == *stackTop); + *stackTop = down; + } + + /* Implemented in gc/RootMarking.cpp. */ + inline void trace(JSTracer *trc); + static void traceAll(JSTracer *trc); + static void traceAllWrappers(JSTracer *trc); + + protected: + AutoGCRooter * const down; + + /* + * Discriminates actual subclass of this being used. If non-negative, the + * subclass roots an array of values of the length stored in this field. + * If negative, meaning is indicated by the corresponding value in the enum + * below. Any other negative value indicates some deeper problem such as + * memory corruption. + */ + ptrdiff_t tag_; + + enum { + VALARRAY = -2, /* js::AutoValueArray */ + PARSER = -3, /* js::frontend::Parser */ + SHAPEVECTOR = -4, /* js::AutoShapeVector */ + IDARRAY = -6, /* js::AutoIdArray */ + DESCVECTOR = -7, /* js::AutoPropDescVector */ + VALVECTOR = -10, /* js::AutoValueVector */ + IDVECTOR = -13, /* js::AutoIdVector */ + OBJVECTOR = -14, /* js::AutoObjectVector */ + STRINGVECTOR =-15, /* js::AutoStringVector */ + SCRIPTVECTOR =-16, /* js::AutoScriptVector */ + NAMEVECTOR = -17, /* js::AutoNameVector */ + HASHABLEVALUE=-18, /* js::HashableValue */ + IONMASM = -19, /* js::jit::MacroAssembler */ + IONALLOC = -20, /* js::jit::AutoTempAllocatorRooter */ + WRAPVECTOR = -21, /* js::AutoWrapperVector */ + WRAPPER = -22, /* js::AutoWrapperRooter */ + OBJOBJHASHMAP=-23, /* js::AutoObjectObjectHashMap */ + OBJU32HASHMAP=-24, /* js::AutoObjectUnsigned32HashMap */ + OBJHASHSET = -25, /* js::AutoObjectHashSet */ + JSONPARSER = -26, /* js::JSONParser */ + CUSTOM = -27, /* js::CustomAutoRooter */ + FUNVECTOR = -28 /* js::AutoFunctionVector */ + }; + + private: + AutoGCRooter ** const stackTop; + + /* No copy or assignment semantics. */ + AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE; + void operator=(AutoGCRooter &ida) MOZ_DELETE; +}; + } /* namespace JS */ namespace js { From fe3022224ccffc1c4261f5b6dd2dee3a4de2214a Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 9 Jun 2014 10:48:26 -0700 Subject: [PATCH 05/52] Bug 1022396 - Remove Number.toInteger. r=jorendorff --HG-- extra : rebase_source : b9083a824d6a436f7da4c9e158cb78b4ba81fb8c --- .../jit-test/tests/basic/number-tointeger.js | 20 ------------------- js/src/jsnum.cpp | 17 ---------------- 2 files changed, 37 deletions(-) delete mode 100644 js/src/jit-test/tests/basic/number-tointeger.js diff --git a/js/src/jit-test/tests/basic/number-tointeger.js b/js/src/jit-test/tests/basic/number-tointeger.js deleted file mode 100644 index bbe68de5f8a2..000000000000 --- a/js/src/jit-test/tests/basic/number-tointeger.js +++ /dev/null @@ -1,20 +0,0 @@ -assertEq(Number.toInteger(4), 4); -assertEq(Number.toInteger(4.), 4); -assertEq(Number.toInteger(4.3), 4); -assertEq(Number.toInteger(-4), -4); -assertEq(Number.toInteger(-4.), -4); -assertEq(Number.toInteger(-4.3), -4); -assertEq(Number.toInteger(0.), 0.); -assertEq(Number.toInteger(-0.), -0.); -assertEq(Number.toInteger(Infinity), Infinity); -assertEq(Number.toInteger(-Infinity), -Infinity); -assertEq(Number.toInteger(NaN), 0); -assertEq(Number.toInteger(null), 0); -assertEq(Number.toInteger(undefined), 0); -assertEq(Number.toInteger(true), 1); -assertEq(Number.toInteger(false), 0); -assertEq(Number.toInteger({valueOf : function () { return 4; }}), 4); -assertEq(Number.toInteger({valueOf : function () { return 4.3; }}), 4); -assertEq(Number.toInteger({valueOf : function () { return "4"; }}), 4); -assertEq(Number.toInteger({valueOf : function () { return {};}}), 0); -assertEq(Number.toInteger(), 0); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 9ce6d7bd2f7b..e64a5300b161 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1060,22 +1060,6 @@ Number_isInteger(JSContext *cx, unsigned argc, Value *vp) return true; } -// ES6 drafult ES6 15.7.3.13 -static bool -Number_toInteger(JSContext *cx, unsigned argc, Value *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - if (args.length() < 1) { - args.rval().setInt32(0); - return true; - } - double asint; - if (!ToInteger(cx, args[0], &asint)) - return false; - args.rval().setNumber(asint); - return true; -} - static const JSFunctionSpec number_static_methods[] = { JS_SELF_HOSTED_FN("isFinite", "Number_isFinite", 1,0), @@ -1084,7 +1068,6 @@ static const JSFunctionSpec number_static_methods[] = { JS_SELF_HOSTED_FN("isSafeInteger", "Number_isSafeInteger", 1,0), JS_FN("parseFloat", num_parseFloat, 1, 0), JS_FN("parseInt", num_parseInt, 2, 0), - JS_FN("toInteger", Number_toInteger, 1, 0), JS_FS_END }; From dc643a63892410c03a1463ac7a279b3a0c8d3910 Mon Sep 17 00:00:00 2001 From: Steve Workman Date: Sat, 7 Jun 2014 10:04:51 -0700 Subject: [PATCH 06/52] Bug 1011503 - Remove external addresses from test_speculative_connect.js r=mcmanus --- netwerk/test/unit/test_speculative_connect.js | 77 +------------------ 1 file changed, 2 insertions(+), 75 deletions(-) diff --git a/netwerk/test/unit/test_speculative_connect.js b/netwerk/test/unit/test_speculative_connect.js index 89179ddf0b49..c730936db87a 100644 --- a/netwerk/test/unit/test_speculative_connect.js +++ b/netwerk/test/unit/test_speculative_connect.js @@ -37,43 +37,18 @@ var localIPv6Literals = ]; var localIPLiterals = localIPv4Literals.concat(localIPv6Literals); -/** Example remote IP addresses - * - * Note: The test environment may not have external network access, so - * resolving hostnames may not be possible. Thus, literals are used here, and - * should be directly converted by the stub resolver to IP addresses. - */ -var remoteIPv4Literals = - [ "93.184.216.119", // example.com - "74.125.239.130", // google.com - "63.245.217.105", // mozilla.org - "173.252.110.27" // facebook.com - ]; - -var remoteIPv6Literals = - [ "2607:f8b0:4005:802::1009", // google.com - "2620:101:8008:5::2:1", // mozilla.org - "2a03:2880:2110:df07:face:b00c::1" // facebook.com - ]; - -var remoteIPLiterals = remoteIPv4Literals.concat(remoteIPv6Literals); - /** Test function list and descriptions. */ var testList = [ test_speculative_connect, test_hostnames_resolving_to_local_addresses, - test_hostnames_resolving_to_remote_addresses, - test_proxies_with_local_addresses, - test_proxies_with_remote_addresses + test_proxies_with_local_addresses ]; var testDescription = [ "Expect pass with localhost", "Expect failure with resolved local IPs", - "Expect success with resolved remote IPs", - "Expect failure for proxies with local IPs", - "Expect success for proxies with remote IPs" + "Expect failure for proxies with local IPs" ]; var testIdx = 0; @@ -250,30 +225,6 @@ function test_hostnames_resolving_to_local_addresses() { test_hostnames_resolving_to_addresses(host, false, next); } -/** - * test_hostnames_resolving_to_remote_addresses - * - * Creates an nsISocketTransport and simulates a speculative connect request - * for a hostname that resolves to a local IP address. - * Runs asynchronously; on test success (i.e. failure to connect), the callback - * will call this function again until all hostnames in the test list are done. - * - * Note: This test also uses an IP literal for the hostname. This should be ok, - * as the socket layer will ask for the hostname to be resolved anyway, and DNS - * code should return a numerical version of the address internally. - */ -function test_hostnames_resolving_to_remote_addresses() { - if (hostIdx >= remoteIPLiterals.length) { - // No more remote IP addresses; move on. - next_test(); - return; - } - var host = remoteIPLiterals[hostIdx++]; - // Test another remote IP address when the current one is done. - var next = test_hostnames_resolving_to_remote_addresses; - test_hostnames_resolving_to_addresses(host, true, next); -} - /** test_speculative_connect_with_host_list * * Common test function for resolved proxy hosts. Takes a list of hosts, a @@ -348,30 +299,6 @@ function test_proxies_with_local_addresses() { test_proxies(host, false, next); } -/** - * test_proxies_with_remote_addresses - * - * Creates an nsISocketTransport and simulates a speculative connect request - * for a proxy that resolves to a local IP address. - * Runs asynchronously; on test success (i.e. failure to connect), the callback - * will call this function again until all proxies in the test list are done. - * - * Note: This test also uses an IP literal for the proxy. This should be ok, - * as the socket layer will ask for the proxy to be resolved anyway, and DNS - * code should return a numerical version of the address internally. - */ -function test_proxies_with_remote_addresses() { - if (hostIdx >= remoteIPLiterals.length) { - // No more local IP addresses; move on. - next_test(); - return; - } - var host = remoteIPLiterals[hostIdx++]; - // Test another local IP address when the current one is done. - var next = test_proxies_with_remote_addresses; - test_proxies(host, true, next); -} - /** next_test * * Calls the next test in testList. Each test is responsible for calling this From 3bea7e30068f3078c33d3e800c6b54607ecbb405 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 9 Jun 2014 14:02:38 -0400 Subject: [PATCH 07/52] Bug 1018387 - Log the composition bounds in layer dumps. r=Cwiiis --- gfx/layers/LayersLogging.cpp | 1 + gfx/layers/LayersLogging.h | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/gfx/layers/LayersLogging.cpp b/gfx/layers/LayersLogging.cpp index dfe235367595..09137aa5ef91 100644 --- a/gfx/layers/LayersLogging.cpp +++ b/gfx/layers/LayersLogging.cpp @@ -118,6 +118,7 @@ AppendToString(nsACString& s, const FrameMetrics& m, { s += pfx; AppendToString(s, m.mViewport, "{ viewport="); + AppendToString(s, m.mCompositionBounds, " cb="); AppendToString(s, m.GetScrollOffset(), " viewportScroll="); AppendToString(s, m.mDisplayPort, " displayport="); AppendToString(s, m.mCriticalDisplayPort, " critdp="); diff --git a/gfx/layers/LayersLogging.h b/gfx/layers/LayersLogging.h index 4e7b1ae89458..693794f0d149 100644 --- a/gfx/layers/LayersLogging.h +++ b/gfx/layers/LayersLogging.h @@ -80,6 +80,18 @@ AppendToString(nsACString& s, const mozilla::gfx::RectTyped& r, return s += sfx; } +template +nsACString& +AppendToString(nsACString& s, const mozilla::gfx::IntRectTyped& r, + const char* pfx="", const char* sfx="") +{ + s += pfx; + s.AppendPrintf( + "(x=%d, y=%d, w=%d, h=%d)", + r.x, r.y, r.width, r.height); + return s += sfx; +} + nsACString& AppendToString(nsACString& s, const nsIntRegion& r, const char* pfx="", const char* sfx=""); From 8eee2dac6d4fdc5571bfcd51fe4257a56f07c9fe Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 9 Jun 2014 14:02:39 -0400 Subject: [PATCH 08/52] Bug 1018387 - Add some logging for the tile drawing code. r=Cwiiis --- gfx/layers/TiledLayerBuffer.h | 19 ++++++++++++ gfx/layers/client/ClientThebesLayer.cpp | 5 +++ gfx/layers/client/ClientTiledThebesLayer.cpp | 32 ++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/gfx/layers/TiledLayerBuffer.h b/gfx/layers/TiledLayerBuffer.h index dd965dd909fa..7d5a0021a872 100644 --- a/gfx/layers/TiledLayerBuffer.h +++ b/gfx/layers/TiledLayerBuffer.h @@ -17,6 +17,7 @@ #include "nsRect.h" // for nsIntRect #include "nsRegion.h" // for nsIntRegion #include "nsTArray.h" // for nsTArray +#include "prlog.h" // for PR_LOG #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 #include @@ -25,6 +26,24 @@ namespace mozilla { namespace layers { +// To get this logging, you need PR logging enabled (either by +// doing a debug build, or #define'ing FORCE_PR_LOG at the top +// of a .cpp file), and then run with NSPR_LOG_MODULES=tiling:5 +// in your environment at runtime. +#ifdef PR_LOGGING +# define TILING_PRLOG(_args) PR_LOG(gTilingLog, PR_LOG_DEBUG, _args) +# define TILING_PRLOG_OBJ(_args, obj) \ + { \ + nsAutoCString tmpstr; \ + AppendToString(tmpstr, obj); \ + PR_LOG(gTilingLog, PR_LOG_DEBUG, _args); \ + } + extern PRLogModuleInfo* gTilingLog; +#else +# define TILING_PRLOG(_args) +# define TILING_PRLOG_OBJ(_args, obj) +#endif + // An abstract implementation of a tile buffer. This code covers the logic of // moving and reusing tiles and leaves the validation up to the implementor. To // avoid the overhead of virtual dispatch, we employ the curiously recurring diff --git a/gfx/layers/client/ClientThebesLayer.cpp b/gfx/layers/client/ClientThebesLayer.cpp index 0abfc41de74b..1aa3e22b816e 100644 --- a/gfx/layers/client/ClientThebesLayer.cpp +++ b/gfx/layers/client/ClientThebesLayer.cpp @@ -28,6 +28,8 @@ namespace mozilla { namespace layers { +PRLogModuleInfo* gTilingLog; + using namespace mozilla::gfx; void @@ -143,6 +145,9 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint) (AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_OPENGL || AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D9 || AsShadowForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_D3D11)) { + if (!gTilingLog) { + gTilingLog = PR_NewLogModule("tiling"); + } if (gfxPrefs::LayersUseSimpleTiles()) { nsRefPtr layer = new SimpleClientTiledThebesLayer(this); diff --git a/gfx/layers/client/ClientTiledThebesLayer.cpp b/gfx/layers/client/ClientTiledThebesLayer.cpp index 9671c5a8bfcc..be81bd6d977d 100644 --- a/gfx/layers/client/ClientTiledThebesLayer.cpp +++ b/gfx/layers/client/ClientTiledThebesLayer.cpp @@ -2,6 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// Uncomment this to enable the TILING_PRLOG stuff in this file +// for release builds. To get the output you need to have +// NSPR_LOG_MODULES=tiling:5 in your environment at runtime. +// #define FORCE_PR_LOG + #include "ClientTiledThebesLayer.h" #include "FrameMetrics.h" // for FrameMetrics #include "Units.h" // for ScreenIntRect, CSSPoint, etc @@ -18,6 +23,7 @@ #include "mozilla/mozalloc.h" // for operator delete, etc #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsRect.h" // for nsIntRect +#include "LayersLogging.h" namespace mozilla { namespace layers { @@ -117,6 +123,9 @@ ClientTiledThebesLayer::BeginPaint() return; } + TILING_PRLOG(("TILING 0x%p: Found scrollAncestor 0x%p and displayPortAncestor 0x%p\n", this, + scrollAncestor, displayPortAncestor)); + const FrameMetrics& scrollMetrics = scrollAncestor->GetFrameMetrics(); const FrameMetrics& displayportMetrics = displayPortAncestor->GetFrameMetrics(); @@ -138,6 +147,7 @@ ClientTiledThebesLayer::BeginPaint() mPaintData.mCriticalDisplayPort = LayoutDeviceIntRect::ToUntyped(RoundedOut( ApplyParentLayerToLayoutTransform(mPaintData.mTransformDisplayPortToLayoutDevice, criticalDisplayPort))); + TILING_PRLOG_OBJ(("TILING 0x%p: Critical displayport %s\n", this, tmpstr.get()), mPaintData.mCriticalDisplayPort); // Compute the viewport that applies to this layer in the LayoutDevice // space of this layer. @@ -146,10 +156,12 @@ ClientTiledThebesLayer::BeginPaint() + displayportMetrics.mCompositionBounds.TopLeft(); mPaintData.mViewport = ApplyParentLayerToLayoutTransform( mPaintData.mTransformDisplayPortToLayoutDevice, viewport); + TILING_PRLOG_OBJ(("TILING 0x%p: Viewport %s\n", this, tmpstr.get()), mPaintData.mViewport); // Store the resolution from the displayport ancestor layer. Because this is Gecko-side, // before any async transforms have occurred, we can use the zoom for this. mPaintData.mResolution = displayportMetrics.GetZoomToParent(); + TILING_PRLOG(("TILING 0x%p: Resolution %f\n", this, mPaintData.mResolution.scale)); // Store the applicable composition bounds in this layer's LayoutDevice units. gfx3DMatrix layoutDeviceToCompBounds = @@ -157,9 +169,11 @@ ClientTiledThebesLayer::BeginPaint() mPaintData.mCompositionBounds = TransformTo( layoutDeviceToCompBounds.Inverse(), scrollMetrics.mCompositionBounds / scrollMetrics.GetParentResolution()); + TILING_PRLOG_OBJ(("TILING 0x%p: Composition bounds %s\n", this, tmpstr.get()), mPaintData.mCompositionBounds); // Calculate the scroll offset since the last transaction mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoomToParent(); + TILING_PRLOG_OBJ(("TILING 0x%p: Scroll offset %s\n", this, tmpstr.get()), mPaintData.mScrollOffset); } void @@ -172,6 +186,7 @@ ClientTiledThebesLayer::EndPaint(bool aFinish) mPaintData.mLastScrollOffset = mPaintData.mScrollOffset; mPaintData.mPaintFinished = true; mPaintData.mFirstPaint = false; + TILING_PRLOG(("TILING 0x%p: Paint finished\n", this)); } void @@ -197,6 +212,9 @@ ClientTiledThebesLayer::RenderLayer() mValidRegion = nsIntRegion(); } + TILING_PRLOG_OBJ(("TILING 0x%p: Initial visible region %s\n", this, tmpstr.get()), mVisibleRegion); + TILING_PRLOG_OBJ(("TILING 0x%p: Initial valid region %s\n", this, tmpstr.get()), mValidRegion); + nsIntRegion invalidRegion = mVisibleRegion; invalidRegion.Sub(invalidRegion, mValidRegion); if (invalidRegion.IsEmpty()) { @@ -239,6 +257,9 @@ ClientTiledThebesLayer::RenderLayer() return; } + TILING_PRLOG_OBJ(("TILING 0x%p: Valid region %s\n", this, tmpstr.get()), mValidRegion); + TILING_PRLOG_OBJ(("TILING 0x%p: Visible region %s\n", this, tmpstr.get()), mVisibleRegion); + // Make sure that tiles that fall outside of the visible region are // discarded on the first update. if (!ClientManager()->IsRepeatTransaction()) { @@ -269,6 +290,8 @@ ClientTiledThebesLayer::RenderLayer() } } + TILING_PRLOG_OBJ(("TILING 0x%p: Invalid region %s\n", this, tmpstr.get()), invalidRegion); + if (!invalidRegion.IsEmpty() && mPaintData.mLowPrecisionPaintCount == 0) { bool updatedBuffer = false; // Only draw progressively when the resolution is unchanged. @@ -284,6 +307,8 @@ ClientTiledThebesLayer::RenderLayer() oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort); } + TILING_PRLOG_OBJ(("TILING 0x%p: Progressive update with old valid region %s\n", this, tmpstr.get()), oldValidRegion); + updatedBuffer = mContentClient->mTiledBuffer.ProgressiveUpdate(mValidRegion, invalidRegion, oldValidRegion, &mPaintData, @@ -294,6 +319,10 @@ ClientTiledThebesLayer::RenderLayer() if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort); } + + TILING_PRLOG_OBJ(("TILING 0x%p: Painting: valid region %s\n", this, tmpstr.get()), mValidRegion); + TILING_PRLOG_OBJ(("TILING 0x%p: and invalid region %s\n", this, tmpstr.get()), invalidRegion); + mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution); mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data); @@ -318,6 +347,9 @@ ClientTiledThebesLayer::RenderLayer() } } + TILING_PRLOG_OBJ(("TILING 0x%p: Low-precision valid region is %s\n", this, tmpstr.get()), mLowPrecisionValidRegion); + TILING_PRLOG_OBJ(("TILING 0x%p: Low-precision invalid region is %s\n", this, tmpstr.get()), lowPrecisionInvalidRegion); + // Render the low precision buffer, if there's area to invalidate and the // visible region is larger than the critical display port. bool updatedLowPrecision = false; From 0d3a73d431a8fed3f52e4eedbb2398e5815499d1 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 9 Jun 2014 14:02:39 -0400 Subject: [PATCH 09/52] Bug 1018387 - Update various variables and comments to reflect the fact that the values are in layer pixels and not layout device pixels. r=Cwiiis --- gfx/layers/client/ClientTiledThebesLayer.cpp | 45 ++++++++++---------- gfx/layers/client/TiledContentClient.cpp | 33 +++++++------- gfx/layers/client/TiledContentClient.h | 15 +++---- layout/base/Units.h | 3 ++ 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/gfx/layers/client/ClientTiledThebesLayer.cpp b/gfx/layers/client/ClientTiledThebesLayer.cpp index be81bd6d977d..248d788c72fe 100644 --- a/gfx/layers/client/ClientTiledThebesLayer.cpp +++ b/gfx/layers/client/ClientTiledThebesLayer.cpp @@ -58,10 +58,10 @@ ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) aAttrs = ThebesLayerAttributes(GetValidRegion()); } -static LayoutDeviceRect -ApplyParentLayerToLayoutTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect) +static LayerRect +ApplyParentLayerToLayerTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect) { - return TransformTo(aTransform, aParentLayerRect); + return TransformTo(aTransform, aParentLayerRect); } static gfx3DMatrix @@ -130,23 +130,22 @@ ClientTiledThebesLayer::BeginPaint() const FrameMetrics& displayportMetrics = displayPortAncestor->GetFrameMetrics(); // Calculate the transform required to convert ParentLayer space of our - // display port ancestor to the LayoutDevice space of this layer. - gfx3DMatrix layoutDeviceToDisplayPort = + // display port ancestor to the Layer space of this layer. + gfx3DMatrix transformToDisplayPort = GetTransformToAncestorsParentLayer(this, displayPortAncestor); - layoutDeviceToDisplayPort.ScalePost(scrollMetrics.mCumulativeResolution.scale, - scrollMetrics.mCumulativeResolution.scale, - 1.f); + transformToDisplayPort.ScalePost(scrollMetrics.mCumulativeResolution.scale, + scrollMetrics.mCumulativeResolution.scale, + 1.f); - mPaintData.mTransformDisplayPortToLayoutDevice = layoutDeviceToDisplayPort.Inverse(); + mPaintData.mTransformDisplayPortToLayer = transformToDisplayPort.Inverse(); // Compute the critical display port that applies to this layer in the // LayoutDevice space of this layer. ParentLayerRect criticalDisplayPort = (displayportMetrics.mCriticalDisplayPort * displayportMetrics.GetZoomToParent()) + displayportMetrics.mCompositionBounds.TopLeft(); - mPaintData.mCriticalDisplayPort = LayoutDeviceIntRect::ToUntyped(RoundedOut( - ApplyParentLayerToLayoutTransform(mPaintData.mTransformDisplayPortToLayoutDevice, - criticalDisplayPort))); + mPaintData.mCriticalDisplayPort = RoundedOut( + ApplyParentLayerToLayerTransform(mPaintData.mTransformDisplayPortToLayer, criticalDisplayPort)); TILING_PRLOG_OBJ(("TILING 0x%p: Critical displayport %s\n", this, tmpstr.get()), mPaintData.mCriticalDisplayPort); // Compute the viewport that applies to this layer in the LayoutDevice @@ -154,8 +153,8 @@ ClientTiledThebesLayer::BeginPaint() ParentLayerRect viewport = (displayportMetrics.mViewport * displayportMetrics.GetZoomToParent()) + displayportMetrics.mCompositionBounds.TopLeft(); - mPaintData.mViewport = ApplyParentLayerToLayoutTransform( - mPaintData.mTransformDisplayPortToLayoutDevice, viewport); + mPaintData.mViewport = ApplyParentLayerToLayerTransform( + mPaintData.mTransformDisplayPortToLayer, viewport); TILING_PRLOG_OBJ(("TILING 0x%p: Viewport %s\n", this, tmpstr.get()), mPaintData.mViewport); // Store the resolution from the displayport ancestor layer. Because this is Gecko-side, @@ -163,11 +162,11 @@ ClientTiledThebesLayer::BeginPaint() mPaintData.mResolution = displayportMetrics.GetZoomToParent(); TILING_PRLOG(("TILING 0x%p: Resolution %f\n", this, mPaintData.mResolution.scale)); - // Store the applicable composition bounds in this layer's LayoutDevice units. - gfx3DMatrix layoutDeviceToCompBounds = + // Store the applicable composition bounds in this layer's Layer units. + gfx3DMatrix transformToCompBounds = GetTransformToAncestorsParentLayer(this, scrollAncestor); - mPaintData.mCompositionBounds = TransformTo( - layoutDeviceToCompBounds.Inverse(), + mPaintData.mCompositionBounds = TransformTo( + transformToCompBounds.Inverse(), scrollMetrics.mCompositionBounds / scrollMetrics.GetParentResolution()); TILING_PRLOG_OBJ(("TILING 0x%p: Composition bounds %s\n", this, tmpstr.get()), mPaintData.mCompositionBounds); @@ -267,7 +266,7 @@ ClientTiledThebesLayer::RenderLayer() if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { // Make sure that tiles that fall outside of the critical displayport are // discarded on the first update. - mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort); + mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); } } @@ -283,7 +282,7 @@ ClientTiledThebesLayer::RenderLayer() } // Clip the invalid region to the critical display-port - invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort); + invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); if (invalidRegion.IsEmpty() && lowPrecisionInvalidRegion.IsEmpty()) { EndPaint(true); return; @@ -304,7 +303,7 @@ ClientTiledThebesLayer::RenderLayer() nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion(); oldValidRegion.And(oldValidRegion, mVisibleRegion); if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { - oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort); + oldValidRegion.And(oldValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); } TILING_PRLOG_OBJ(("TILING 0x%p: Progressive update with old valid region %s\n", this, tmpstr.get()), oldValidRegion); @@ -317,7 +316,7 @@ ClientTiledThebesLayer::RenderLayer() updatedBuffer = true; mValidRegion = mVisibleRegion; if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { - mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort); + mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)); } TILING_PRLOG_OBJ(("TILING 0x%p: Painting: valid region %s\n", this, tmpstr.get()), mValidRegion); @@ -354,7 +353,7 @@ ClientTiledThebesLayer::RenderLayer() // visible region is larger than the critical display port. bool updatedLowPrecision = false; if (!lowPrecisionInvalidRegion.IsEmpty() && - !nsIntRegion(mPaintData.mCriticalDisplayPort).Contains(mVisibleRegion)) { + !nsIntRegion(LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)).Contains(mVisibleRegion)) { nsIntRegion oldValidRegion = mContentClient->mLowPrecisionTiledBuffer.GetValidRegion(); oldValidRegion.And(oldValidRegion, mVisibleRegion); diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 05a33ddb8657..b7d7176a27c7 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -889,29 +889,29 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile, return aTile; } -static LayoutDeviceRect +static LayerRect TransformCompositionBounds(const ParentLayerRect& aCompositionBounds, const CSSToParentLayerScale& aZoom, const ParentLayerPoint& aScrollOffset, const CSSToParentLayerScale& aResolution, - const gfx3DMatrix& aTransformDisplayPortToLayoutDevice) + const gfx3DMatrix& aTransformDisplayPortToLayer) { // Transform the composition bounds from the space of the displayport ancestor - // layer into the LayoutDevice space of this layer. Do this by + // layer into the Layer space of this layer. Do this by // compensating for the difference in resolution and subtracting the // old composition bounds origin. ParentLayerRect offsetViewportRect = (aCompositionBounds / aZoom) * aResolution; offsetViewportRect.MoveBy(-aScrollOffset); gfxRect transformedViewport = - aTransformDisplayPortToLayoutDevice.TransformBounds( + aTransformDisplayPortToLayer.TransformBounds( gfxRect(offsetViewportRect.x, offsetViewportRect.y, offsetViewportRect.width, offsetViewportRect.height)); - return LayoutDeviceRect(transformedViewport.x, - transformedViewport.y, - transformedViewport.width, - transformedViewport.height); + return LayerRect(transformedViewport.x, + transformedViewport.y, + transformedViewport.width, + transformedViewport.height); } bool @@ -976,26 +976,27 @@ ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInval } } - LayoutDeviceRect transformedCompositionBounds = + LayerRect transformedCompositionBounds = TransformCompositionBounds(compositionBounds, zoom, aPaintData->mScrollOffset, - aPaintData->mResolution, aPaintData->mTransformDisplayPortToLayoutDevice); + aPaintData->mResolution, aPaintData->mTransformDisplayPortToLayer); // Paint tiles that have stale content or that intersected with the screen // at the time of issuing the draw command in a single transaction first. // This is to avoid rendering glitches on animated page content, and when // layers change size/shape. - LayoutDeviceRect typedCoherentUpdateRect = + LayerRect typedCoherentUpdateRect = transformedCompositionBounds.Intersect(aPaintData->mCompositionBounds); // Offset by the viewport origin, as the composition bounds are stored in // Layer space and not LayoutDevice space. + // TODO(kats): does this make sense? typedCoherentUpdateRect.MoveBy(aPaintData->mViewport.TopLeft()); // Convert to untyped to intersect with the invalid region. - nsIntRect roundedCoherentUpdateRect = - LayoutDeviceIntRect::ToUntyped(RoundedOut(typedCoherentUpdateRect)); + nsIntRect untypedCoherentUpdateRect(LayerIntRect::ToUntyped( + RoundedOut(typedCoherentUpdateRect))); - aRegionToPaint.And(aInvalidRegion, roundedCoherentUpdateRect); + aRegionToPaint.And(aInvalidRegion, untypedCoherentUpdateRect); aRegionToPaint.Or(aRegionToPaint, staleRegion); bool drawingStale = !aRegionToPaint.IsEmpty(); if (!drawingStale) { @@ -1004,8 +1005,8 @@ ClientTiledLayerBuffer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInval // Prioritise tiles that are currently visible on the screen. bool paintVisible = false; - if (aRegionToPaint.Intersects(roundedCoherentUpdateRect)) { - aRegionToPaint.And(aRegionToPaint, roundedCoherentUpdateRect); + if (aRegionToPaint.Intersects(untypedCoherentUpdateRect)) { + aRegionToPaint.And(aRegionToPaint, untypedCoherentUpdateRect); paintVisible = true; } diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index cf1d7ac03681..2bb33930ebdb 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -255,26 +255,23 @@ struct BasicTiledLayerPaintData { /* * The transform matrix to go from the display port layer's ParentLayer - * units to this layer's LayoutDevice units. The "display port layer" is + * units to this layer's Layer units. The "display port layer" is * the closest ancestor layer with a displayport. */ - gfx3DMatrix mTransformDisplayPortToLayoutDevice; + gfx3DMatrix mTransformDisplayPortToLayer; /* * The critical displayport of the content from the nearest ancestor layer * that represents scrollable content with a display port set. Empty if a * critical displayport is not set. - * - * This is in LayoutDevice coordinates, but is stored as an nsIntRect for - * convenience when intersecting with the layer's mValidRegion. */ - nsIntRect mCriticalDisplayPort; + LayerIntRect mCriticalDisplayPort; /* * The viewport of the content from the nearest ancestor layer that * represents scrollable content with a display port set. */ - LayoutDeviceRect mViewport; + LayerRect mViewport; /* * The render resolution of the document that the content this layer @@ -283,11 +280,11 @@ struct BasicTiledLayerPaintData { CSSToParentLayerScale mResolution; /* - * The composition bounds of the layer, in LayoutDevice coordinates. This is + * The composition bounds of the layer, in Layer coordinates. This is * used to make sure that tiled updates to regions that are visible to the * user are grouped coherently. */ - LayoutDeviceRect mCompositionBounds; + LayerRect mCompositionBounds; /* * Low precision updates are always executed a tile at a time in repeated diff --git a/layout/base/Units.h b/layout/base/Units.h index f7c26d292c40..fa9f8aacaa3d 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -189,6 +189,9 @@ struct LayoutDevicePixel { * 3) the "widget scale" (see nsIWidget::GetDefaultScale) */ struct LayerPixel { + static nsIntRect ToUntyped(const LayerIntRect& aRect) { + return nsIntRect(aRect.x, aRect.y, aRect.width, aRect.height); + } }; /* From 4f054304cda1256ccb6180948797b58a966c7124 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 9 Jun 2014 14:02:40 -0400 Subject: [PATCH 10/52] Bug 1018387 - Fix some calculations that were wrong because of confusion between LayoutDevice and Layer pixel spaces. r=botond --- gfx/layers/client/ClientTiledThebesLayer.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/gfx/layers/client/ClientTiledThebesLayer.cpp b/gfx/layers/client/ClientTiledThebesLayer.cpp index 248d788c72fe..02374bf5fd22 100644 --- a/gfx/layers/client/ClientTiledThebesLayer.cpp +++ b/gfx/layers/client/ClientTiledThebesLayer.cpp @@ -70,6 +70,12 @@ GetTransformToAncestorsParentLayer(Layer* aStart, Layer* aAncestor) gfx::Matrix4x4 transform; Layer* ancestorParent = aAncestor->GetParent(); for (Layer* iter = aStart; iter != ancestorParent; iter = iter->GetParent()) { + if (iter->AsContainerLayer()) { + // If the layer has a non-transient async transform then we need to apply it here + // because it will get applied by the APZ in the compositor as well + const FrameMetrics& metrics = iter->AsContainerLayer()->GetFrameMetrics(); + transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f); + } transform = transform * iter->GetTransform(); } gfx3DMatrix ret; @@ -133,12 +139,15 @@ ClientTiledThebesLayer::BeginPaint() // display port ancestor to the Layer space of this layer. gfx3DMatrix transformToDisplayPort = GetTransformToAncestorsParentLayer(this, displayPortAncestor); - transformToDisplayPort.ScalePost(scrollMetrics.mCumulativeResolution.scale, - scrollMetrics.mCumulativeResolution.scale, - 1.f); mPaintData.mTransformDisplayPortToLayer = transformToDisplayPort.Inverse(); + // Note that below we use GetZoomToParent() in a number of places. Because this + // code runs on the client side, the mTransformScale field of the FrameMetrics + // will not have been set. This can result in incorrect values being returned + // by GetZoomToParent() when we have CSS transforms set on some of these layers. + // This code should be audited and updated as part of fixing bug 993525. + // Compute the critical display port that applies to this layer in the // LayoutDevice space of this layer. ParentLayerRect criticalDisplayPort = @@ -165,9 +174,8 @@ ClientTiledThebesLayer::BeginPaint() // Store the applicable composition bounds in this layer's Layer units. gfx3DMatrix transformToCompBounds = GetTransformToAncestorsParentLayer(this, scrollAncestor); - mPaintData.mCompositionBounds = TransformTo( - transformToCompBounds.Inverse(), - scrollMetrics.mCompositionBounds / scrollMetrics.GetParentResolution()); + mPaintData.mCompositionBounds = ApplyParentLayerToLayerTransform( + transformToCompBounds.Inverse(), ParentLayerRect(scrollMetrics.mCompositionBounds)); TILING_PRLOG_OBJ(("TILING 0x%p: Composition bounds %s\n", this, tmpstr.get()), mPaintData.mCompositionBounds); // Calculate the scroll offset since the last transaction From 1d701608b8c3a811de0a08dae84e52a7c2914aa0 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 9 Jun 2014 14:02:40 -0400 Subject: [PATCH 11/52] Bug 1022398 - Remove declaration for method that was removed a long time ago. r=nical --- gfx/layers/LayersLogging.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gfx/layers/LayersLogging.h b/gfx/layers/LayersLogging.h index 693794f0d149..2617c4e4cb75 100644 --- a/gfx/layers/LayersLogging.h +++ b/gfx/layers/LayersLogging.h @@ -16,7 +16,6 @@ #include "nsRegion.h" // for nsIntRegion #include "nscore.h" // for nsACString, etc -class gfx3DMatrix; struct gfxRGBA; struct nsIntPoint; struct nsIntRect; @@ -46,10 +45,6 @@ nsACString& AppendToString(nsACString& s, const gfxRGBA& c, const char* pfx="", const char* sfx=""); -nsACString& -AppendToString(nsACString& s, const gfx3DMatrix& m, - const char* pfx="", const char* sfx=""); - nsACString& AppendToString(nsACString& s, const nsIntPoint& p, const char* pfx="", const char* sfx=""); From 2fa097201c2299eb8d0c82f0a3ecb5867e8502a1 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas Date: Wed, 4 Jun 2014 20:11:06 +0200 Subject: [PATCH 12/52] Bug 1020257 - Dispatch hud events on the main window for system app related events. r=janx --- b2g/chrome/content/devtools.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/b2g/chrome/content/devtools.js b/b2g/chrome/content/devtools.js index e2b5ab5e5e21..2d5a602474d8 100644 --- a/b2g/chrome/content/devtools.js +++ b/b2g/chrome/content/devtools.js @@ -272,7 +272,14 @@ Target.prototype = { }, _send: function target_send(data) { - shell.sendEvent(this.frame, 'developer-hud-update', Cu.cloneInto(data, this.frame)); + let frame = this.frame; + + let systemapp = document.querySelector('#systemapp'); + if (this.frame === systemapp) { + frame = getContentWindow(); + } + + shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame)); } }; From 20266b3d5d09e18d8bf5fc44acfe81f8bb2391b1 Mon Sep 17 00:00:00 2001 From: Garvan Keeley Date: Sun, 8 Jun 2014 22:52:53 -0700 Subject: [PATCH 13/52] Bug 1018379 - Use wifi scanner as the sole the heartbeat that drives location updates, shorten the wifi scanner wait to 5s to ensure this (also stop and restart the scanner on WifiGeoPositionProvider.startup() to ensure this). r=jdm --- dom/system/NetworkGeolocationProvider.js | 55 ++++++++++++++---------- netwerk/wifi/nsWifiAccessPoint.cpp | 4 +- netwerk/wifi/nsWifiMonitor.h | 2 + netwerk/wifi/nsWifiScannerDBus.cpp | 2 +- netwerk/wifi/nsWifiScannerFreeBSD.cpp | 2 +- netwerk/wifi/nsWifiScannerMac.cpp | 2 +- netwerk/wifi/nsWifiScannerSolaris.cpp | 2 +- netwerk/wifi/nsWifiScannerWin.cpp | 2 +- 8 files changed, 42 insertions(+), 29 deletions(-) diff --git a/dom/system/NetworkGeolocationProvider.js b/dom/system/NetworkGeolocationProvider.js index 60fec97e4f4c..8bdc7f4e5935 100755 --- a/dom/system/NetworkGeolocationProvider.js +++ b/dom/system/NetworkGeolocationProvider.js @@ -14,14 +14,10 @@ const SETTING_CHANGED_TOPIC = "mozsettings-changed"; let gLoggingEnabled = false; -// if we don't see any wifi responses in 5 seconds, send the request. -let gTimeToWaitBeforeSending = 5000; //ms +let gLocationRequestTimeout = 5000; let gWifiScanningEnabled = true; -let gWifiResults; - let gCellScanningEnabled = false; -let gCellResults; function LOG(aMsg) { if (gLoggingEnabled) { @@ -59,7 +55,7 @@ function WifiGeoPositionProvider() { } catch (e) {} try { - gTimeToWaitBeforeSending = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending"); + gLocationRequestTimeout = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending"); } catch (e) {} try { @@ -123,12 +119,16 @@ WifiGeoPositionProvider.prototype = { } if (gWifiScanningEnabled && Cc["@mozilla.org/wifi/monitor;1"]) { - this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor); + if (this.wifiService) { + this.wifiService.stopWatching(this); + } + this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor); this.wifiService.startWatching(this); } + // wifi thread triggers WifiGeoPositionProvider to proceed, with no wifi, do manual timeout this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); this.timeoutTimer.initWithCallback(this, - gTimeToWaitBeforeSending, + gLocationRequestTimeout, this.timeoutTimer.TYPE_REPEATING_SLACK); LOG("startup called."); }, @@ -163,7 +163,6 @@ WifiGeoPositionProvider.prototype = { }, onChange: function(accessPoints) { - function isPublic(ap) { let mask = "_nomap" let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length); @@ -181,18 +180,19 @@ WifiGeoPositionProvider.prototype = { return { 'macAddress': ap.mac, 'signalStrength': ap.signal }; }; + let wifiData = null; if (accessPoints) { - gWifiResults = accessPoints.filter(isPublic).sort(sort).map(encode); - } else { - gWifiResults = null; + wifiData = accessPoints.filter(isPublic).sort(sort).map(encode); } + this.sendLocationRequest(wifiData); }, onError: function (code) { LOG("wifi error: " + code); + this.sendLocationRequest(null); }, - updateMobileInfo: function() { + getMobileInfo: function() { LOG("updateMobileInfo called"); try { let radioService = Cc["@mozilla.org/ril;1"] @@ -216,11 +216,20 @@ WifiGeoPositionProvider.prototype = { } return result; } catch (e) { - gCellResults = null; + return null; } }, notify: function (timeoutTimer) { + // If Wifi scanning is disabled, then we can not depend on that for the + // heartbeat that drives location updates. Instead, just use a timer which + // will drive the update. + if (gWifiScanningEnabled == false) { + this.sendLocationRequest(null); + } + }, + + sendLocationRequest: function (wifiData) { let url = Services.urlFormatter.formatURLPref("geo.wifi.uri"); let listener = this.listener; LOG("Sending request: " + url + "\n"); @@ -258,19 +267,19 @@ WifiGeoPositionProvider.prototype = { listener.update(newLocation); }; - if (gCellScanningEnabled) { - this.updateMobileInfo(); + let data = {}; + if (wifiData) { + data.wifiAccessPoints = wifiData; } - let data = {}; - if (gWifiResults) { - data.wifiAccessPoints = gWifiResults; - } - if (gCellResults) { - data.cellTowers = gCellResults; + if (gCellScanningEnabled) { + let cellData = this.getMobileInfo(); + if (cellData) { + data.cellTowers = cellData; + } } + data = JSON.stringify(data); - gWifiResults = gCellResults = null; LOG("sending " + data); xhr.send(data); }, diff --git a/netwerk/wifi/nsWifiAccessPoint.cpp b/netwerk/wifi/nsWifiAccessPoint.cpp index f2ae1ff0116e..55a6df5dadfc 100644 --- a/netwerk/wifi/nsWifiAccessPoint.cpp +++ b/netwerk/wifi/nsWifiAccessPoint.cpp @@ -21,6 +21,7 @@ nsWifiAccessPoint::nsWifiAccessPoint() mMac[0] = '\0'; mSsid[0] = '\0'; mSsidLen = 0; + mSignal = -1000; } nsWifiAccessPoint::~nsWifiAccessPoint() @@ -70,7 +71,8 @@ bool AccessPointsEqual(nsCOMArray& a, nsCOMArray%s | %s->%s\n", a[i]->mSsid, b[j]->mSsid, a[i]->mMac, b[j]->mMac)); if (!strcmp(a[i]->mSsid, b[j]->mSsid) && - !strcmp(a[i]->mMac, b[j]->mMac)) { + !strcmp(a[i]->mMac, b[j]->mMac) && + a[i]->mSignal == b[j]->mSignal) { found = true; } } diff --git a/netwerk/wifi/nsWifiMonitor.h b/netwerk/wifi/nsWifiMonitor.h index 3121eb284921..dbede105155c 100644 --- a/netwerk/wifi/nsWifiMonitor.h +++ b/netwerk/wifi/nsWifiMonitor.h @@ -28,6 +28,8 @@ extern PRLogModuleInfo *gWifiMonitorLog; class nsWifiAccessPoint; +#define kDefaultWifiScanInterval 5 /* seconds */ + class nsWifiListener { public: diff --git a/netwerk/wifi/nsWifiScannerDBus.cpp b/netwerk/wifi/nsWifiScannerDBus.cpp index 5042a8d056ae..5a30ad9ac7bb 100644 --- a/netwerk/wifi/nsWifiScannerDBus.cpp +++ b/netwerk/wifi/nsWifiScannerDBus.cpp @@ -332,7 +332,7 @@ nsWifiMonitor::DoScan() LOG(("waiting on monitor\n")); mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mon.Wait(PR_SecondsToInterval(60)); + mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval)); } return NS_OK; diff --git a/netwerk/wifi/nsWifiScannerFreeBSD.cpp b/netwerk/wifi/nsWifiScannerFreeBSD.cpp index 74bc82eaf52a..bdf171eb6cf5 100644 --- a/netwerk/wifi/nsWifiScannerFreeBSD.cpp +++ b/netwerk/wifi/nsWifiScannerFreeBSD.cpp @@ -159,7 +159,7 @@ nsWifiMonitor::DoScan() LOG(("waiting on monitor\n")); ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mon.Wait(PR_SecondsToInterval(60)); + mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval)); } while (mKeepGoing); diff --git a/netwerk/wifi/nsWifiScannerMac.cpp b/netwerk/wifi/nsWifiScannerMac.cpp index 9ae80e2abc9b..b8ca682c213f 100644 --- a/netwerk/wifi/nsWifiScannerMac.cpp +++ b/netwerk/wifi/nsWifiScannerMac.cpp @@ -47,7 +47,7 @@ nsWifiMonitor::DoScan() LOG(("waiting on monitor\n")); ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mon.Wait(PR_SecondsToInterval(60)); + mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval)); } while (mKeepGoing); diff --git a/netwerk/wifi/nsWifiScannerSolaris.cpp b/netwerk/wifi/nsWifiScannerSolaris.cpp index d0e3fd49477a..6fbfa0eb7770 100644 --- a/netwerk/wifi/nsWifiScannerSolaris.cpp +++ b/netwerk/wifi/nsWifiScannerSolaris.cpp @@ -142,7 +142,7 @@ nsWifiMonitor::DoScan() LOG(("waiting on monitor\n")); ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mon.Wait(PR_SecondsToInterval(60)); + mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval)); } return NS_OK; diff --git a/netwerk/wifi/nsWifiScannerWin.cpp b/netwerk/wifi/nsWifiScannerWin.cpp index bbf2eff38bd9..12825650da4d 100644 --- a/netwerk/wifi/nsWifiScannerWin.cpp +++ b/netwerk/wifi/nsWifiScannerWin.cpp @@ -123,7 +123,7 @@ nsWifiMonitor::DoScan() LOG(("waiting on monitor\n")); ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mon.Wait(PR_SecondsToInterval(60)); + mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval)); } while (mKeepGoing); From a67822ca53ea6b8bf2620d277c3fa34c675dadbe Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Sun, 8 Jun 2014 22:56:29 -0700 Subject: [PATCH 14/52] Bug 1022279 - NetworkLocationProvider should respect wifi.enabled settings. r=kanru --- dom/system/NetworkGeolocationProvider.js | 47 ++++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/dom/system/NetworkGeolocationProvider.js b/dom/system/NetworkGeolocationProvider.js index 8bdc7f4e5935..bc9b366c2022 100755 --- a/dom/system/NetworkGeolocationProvider.js +++ b/dom/system/NetworkGeolocationProvider.js @@ -9,8 +9,9 @@ const Ci = Components.interfaces; const Cc = Components.classes; const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE; -const SETTING_DEBUG_ENABLED = "geolocation.debugging.enabled"; -const SETTING_CHANGED_TOPIC = "mozsettings-changed"; +const SETTINGS_DEBUG_ENABLED = "geolocation.debugging.enabled"; +const SETTINGS_CHANGED_TOPIC = "mozsettings-changed"; +const SETTINGS_WIFI_ENABLED = "wifi.enabled"; let gLoggingEnabled = false; @@ -80,16 +81,17 @@ WifiGeoPositionProvider.prototype = { listener: null, observe: function(aSubject, aTopic, aData) { - if (aTopic != SETTING_CHANGED_TOPIC) { + if (aTopic != SETTINGS_CHANGED_TOPIC) { return; } try { let setting = JSON.parse(aData); - if (setting.key != SETTING_DEBUG_ENABLED) { - return; + if (setting.key == SETTINGS_DEBUG_ENABLED) { + gLoggingEnabled = setting.value; + } else if (setting.key == SETTINGS_WIFI_ENABLED) { + gWifiScanningEnabled = setting.value; } - gLoggingEnabled = setting.value; } catch (e) { } }, @@ -99,9 +101,21 @@ WifiGeoPositionProvider.prototype = { return; this.started = true; + let self = this; let settingsCallback = { handle: function(name, result) { - gLoggingEnabled = result && result.value === true ? true : false; + if (name == SETTINGS_DEBUG_ENABLED) { + gLoggingEnabled = result; + } else if (name == SETTINGS_WIFI_ENABLED) { + gWifiScanningEnabled = result; + if (self.wifiService) { + self.wifiService.stopWatching(self); + } + if (gWifiScanningEnabled) { + self.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor); + self.wifiService.startWatching(self); + } + } }, handleError: function(message) { @@ -111,9 +125,10 @@ WifiGeoPositionProvider.prototype = { }; try { - Services.obs.addObserver(this, SETTING_CHANGED_TOPIC, false); + Services.obs.addObserver(this, SETTINGS_CHANGED_TOPIC, false); let settings = Cc["@mozilla.org/settingsService;1"].getService(Ci.nsISettingsService); - settings.createLock().get(SETTING_DEBUG_ENABLED, settingsCallback); + settings.createLock().get(SETTINGS_WIFI_ENABLED, settingsCallback); + settings.createLock().get(SETTINGS_DEBUG_ENABLED, settingsCallback); } catch(ex) { // This platform doesn't have the settings interface, and that is just peachy } @@ -125,11 +140,13 @@ WifiGeoPositionProvider.prototype = { this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor); this.wifiService.startWatching(this); } - // wifi thread triggers WifiGeoPositionProvider to proceed, with no wifi, do manual timeout - this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this.timeoutTimer.initWithCallback(this, - gLocationRequestTimeout, - this.timeoutTimer.TYPE_REPEATING_SLACK); + + if (!this.timeoutTimer) { + this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this.timeoutTimer.initWithCallback(this, + gLocationRequestTimeout, + this.timeoutTimer.TYPE_REPEATING_SLACK); + } LOG("startup called."); }, @@ -153,7 +170,7 @@ WifiGeoPositionProvider.prototype = { this.wifiService = null; } - Services.obs.removeObserver(this, SETTING_CHANGED_TOPIC); + Services.obs.removeObserver(this, SETTINGS_CHANGED_TOPIC); this.listener = null; this.started = false; From aeaa4ae5d2e8286c855c7e69931d846da69151aa Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Sun, 8 Jun 2014 22:58:37 -0700 Subject: [PATCH 15/52] Bug 1022283 - Increase the timeout value of the NetworkLocationProvider and clean up its usage. r=kanru --- dom/system/NetworkGeolocationProvider.js | 51 ++++++++++++++++-------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/dom/system/NetworkGeolocationProvider.js b/dom/system/NetworkGeolocationProvider.js index bc9b366c2022..d862711638a9 100755 --- a/dom/system/NetworkGeolocationProvider.js +++ b/dom/system/NetworkGeolocationProvider.js @@ -15,6 +15,17 @@ const SETTINGS_WIFI_ENABLED = "wifi.enabled"; let gLoggingEnabled = false; +/* + The gLocationRequestTimeout controls how long we wait on receiving an update + from the Wifi subsystem. If this timer fires, we believe the Wifi scan has + had a problem and we no longer can use Wifi to position the user this time + around (we will continue to be hopeful that Wifi will recover). + + This timeout value is also used when Wifi scanning is disabled (see + gWifiScanningEnabled). In this case, we use this timer to collect cell/ip + data and xhr it to the location server. +*/ + let gLocationRequestTimeout = 5000; let gWifiScanningEnabled = true; @@ -68,7 +79,7 @@ function WifiGeoPositionProvider() { } catch (e) {} this.wifiService = null; - this.timeoutTimer = null; + this.timer = null; this.started = false; } @@ -96,6 +107,18 @@ WifiGeoPositionProvider.prototype = { } }, + resetTimer: function() { + if (this.timer) { + this.timer.cancel(); + this.timer = null; + } + // wifi thread triggers WifiGeoPositionProvider to proceed, with no wifi, do manual timeout + this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this.timer.initWithCallback(this, + gLocationRequestTimeout, + this.timer.TYPE_REPEATING_SLACK); + }, + startup: function() { if (this.started) return; @@ -141,12 +164,7 @@ WifiGeoPositionProvider.prototype = { this.wifiService.startWatching(this); } - if (!this.timeoutTimer) { - this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this.timeoutTimer.initWithCallback(this, - gLocationRequestTimeout, - this.timeoutTimer.TYPE_REPEATING_SLACK); - } + this.resetTimer(); LOG("startup called."); }, @@ -160,9 +178,9 @@ WifiGeoPositionProvider.prototype = { return; } - if (this.timeoutTimer) { - this.timeoutTimer.cancel(); - this.timeoutTimer = null; + if (this.timer) { + this.timer.cancel(); + this.timer = null; } if(this.wifiService) { @@ -180,6 +198,10 @@ WifiGeoPositionProvider.prototype = { }, onChange: function(accessPoints) { + + // we got some wifi data, rearm the timer. + this.resetTimer(); + function isPublic(ap) { let mask = "_nomap" let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length); @@ -237,13 +259,8 @@ WifiGeoPositionProvider.prototype = { } }, - notify: function (timeoutTimer) { - // If Wifi scanning is disabled, then we can not depend on that for the - // heartbeat that drives location updates. Instead, just use a timer which - // will drive the update. - if (gWifiScanningEnabled == false) { - this.sendLocationRequest(null); - } + notify: function (timer) { + this.sendLocationRequest(null); }, sendLocationRequest: function (wifiData) { From c8fc96bd75610f0905cdd6e5faf63503e9c1a201 Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Sun, 8 Jun 2014 22:58:40 -0700 Subject: [PATCH 16/52] Bug 1022463 - Gonk GPS should default to 10s before trying a a network position. r=kanru --- dom/system/gonk/GonkGPSGeolocationProvider.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.cpp b/dom/system/gonk/GonkGPSGeolocationProvider.cpp index ed21d4e51416..351b28ea7ee6 100644 --- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp @@ -703,10 +703,11 @@ GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *pos // assume the MLS coord is unchanged, and stick with the GPS location const double kMinMLSCoordChangeInMeters = 10; - // if we haven't seen anything from the GPS device for 1s, + // if we haven't seen anything from the GPS device for 10s, // use this network derived location. + const int kMaxGPSDelayBeforeConsideringMLS = 10000; int64_t diff = PR_Now() - provider->mLastGPSDerivedLocationTime; - if (provider->mLocationCallback && diff > kDefaultPeriod + if (provider->mLocationCallback && diff > kMaxGPSDelayBeforeConsideringMLS && delta > kMinMLSCoordChangeInMeters) { provider->mLocationCallback->Update(position); From 11673edafb7f184b1af2a2581b3b6743b833573e Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Mon, 9 Jun 2014 11:45:14 -0700 Subject: [PATCH 17/52] Bug 1022764: Add #ifdef guards around some WebRTC-specific code in MediaManager.cpp. r=jesup --- dom/media/MediaManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 48d9f471f7e2..55eca714a11e 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -45,14 +45,13 @@ #include "MediaEngineDefault.h" #if defined(MOZ_WEBRTC) #include "MediaEngineWebRTC.h" +#include "browser_logging/WebRtcLog.h" #endif #ifdef MOZ_B2G #include "MediaPermissionGonk.h" #endif -#include "browser_logging/WebRtcLog.h" - // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to // GetTickCount() and conflicts with MediaStream::GetCurrentTime. #ifdef GetCurrentTime @@ -1577,7 +1576,9 @@ MediaManager::GetUserMedia(bool aPrivileged, obs->NotifyObservers(req, "getUserMedia:request", nullptr); } +#ifdef MOZ_WEBRTC EnableWebRtcLog(); +#endif return NS_OK; } From ac9615fa0d017b873e821b2b52b8f07e563e1a27 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 9 Jun 2014 14:49:34 -0400 Subject: [PATCH 18/52] Bug 1021290 - More Atomics.h build fixes for clang-cl. r=froydnj This is basically more of bug 932454 --- gfx/layers/apz/src/AsyncPanZoomController.h | 2 +- mfbt/Atomics.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index da2d64645b2e..7efb05e57594 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -9,6 +9,7 @@ #include "CrossProcessMutex.h" #include "mozilla/layers/GeckoContentController.h" +#include "mozilla/layers/APZCTreeManager.h" #include "mozilla/Attributes.h" #include "mozilla/EventForwards.h" #include "mozilla/Monitor.h" @@ -38,7 +39,6 @@ class GestureEventListener; class ContainerLayer; class PCompositorParent; class ViewTransform; -class APZCTreeManager; class AsyncPanZoomAnimation; class FlingAnimation; diff --git a/mfbt/Atomics.h b/mfbt/Atomics.h index b893f64d0eff..fcf86a63fe53 100644 --- a/mfbt/Atomics.h +++ b/mfbt/Atomics.h @@ -866,6 +866,7 @@ template struct IntrinsicAddSub : public IntrinsicApplyHelper { typedef typename IntrinsicApplyHelper::ValueType ValueType; + typedef typename IntrinsicBase::Primitives Primitives; static ValueType add(ValueType& aPtr, ptrdiff_t aAmount) { @@ -893,6 +894,7 @@ struct AtomicIntrinsics : public IntrinsicMemoryOps, public IntrinsicIncDec { typedef typename IntrinsicIncDec::ValueType ValueType; + typedef typename IntrinsicBase::Primitives Primitives; static ValueType or_(ValueType& aPtr, T aVal) { @@ -915,6 +917,9 @@ struct AtomicIntrinsics : public IntrinsicMemoryOps, public IntrinsicIncDec { typedef typename IntrinsicMemoryOps::ValueType ValueType; + // This is required to make us be able to build with MSVC10, for unknown + // reasons. + typedef typename IntrinsicBase::Primitives Primitives; }; } // namespace detail From e96b1004a1599ccf7de1511e86a2e0a873772453 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Mon, 9 Jun 2014 20:59:08 +0200 Subject: [PATCH 19/52] Bug 938186 - HTTP cache v2: introduce DISALLOW_SYNC_CALLBACK for opening cache entries, r=michal --- netwerk/cache2/CacheEntry.cpp | 47 +++++++++++++++++-- netwerk/cache2/CacheEntry.h | 13 +++-- netwerk/cache2/nsICacheStorage.idl | 8 ++++ .../test/unit/test_cache2-01f-basic-async.js | 28 +++++++++++ .../test/unit/test_cache2-24-force-async.js | 42 +++++++++++++++++ netwerk/test/unit/xpcshell.ini | 2 + 6 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 netwerk/test/unit/test_cache2-01f-basic-async.js create mode 100644 netwerk/test/unit/test_cache2-24-force-async.js diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index 6af10d3a2e2f..086f34bf5a5b 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -76,7 +76,7 @@ CacheEntryHandle::~CacheEntryHandle() CacheEntry::Callback::Callback(CacheEntry* aEntry, nsICacheEntryOpenCallback *aCallback, - bool aReadOnly, bool aCheckOnAnyThread) + bool aReadOnly, bool aCheckOnAnyThread, bool aForceAsync) : mEntry(aEntry) , mCallback(aCallback) , mTargetThread(do_GetCurrentThread()) @@ -84,6 +84,7 @@ CacheEntry::Callback::Callback(CacheEntry* aEntry, , mCheckOnAnyThread(aCheckOnAnyThread) , mRecheckAfterWrite(false) , mNotWanted(false) +, mForceAsync(aForceAsync) { MOZ_COUNT_CTOR(CacheEntry::Callback); @@ -101,6 +102,7 @@ CacheEntry::Callback::Callback(CacheEntry::Callback const &aThat) , mCheckOnAnyThread(aThat.mCheckOnAnyThread) , mRecheckAfterWrite(aThat.mRecheckAfterWrite) , mNotWanted(aThat.mNotWanted) +, mForceAsync(aThat.mForceAsync) { MOZ_COUNT_CTOR(CacheEntry::Callback); @@ -131,8 +133,19 @@ void CacheEntry::Callback::ExchangeEntry(CacheEntry* aEntry) mEntry = aEntry; } -nsresult CacheEntry::Callback::OnCheckThread(bool *aOnCheckThread) const +nsresult CacheEntry::Callback::OnCheckThread(bool *aOnCheckThread) { + if (mForceAsync) { + // Drop the flag now. First time we must claim we are not on the proper thread + // what will simply force a post. But, the post does the check again and that + // time we must already tell the true we are on the proper thread otherwise we + // just loop indefinitely. Also, we need to post only once the first + // InvokeCallback for this callback. + mForceAsync = false; + *aOnCheckThread = false; + return NS_OK; + } + if (!mCheckOnAnyThread) { // Check we are on the target return mTargetThread->IsOnCurrentThread(aOnCheckThread); @@ -170,6 +183,7 @@ CacheEntry::CacheEntry(const nsACString& aStorageID, , mIsDoomed(false) , mSecurityInfoLoaded(false) , mPreventCallbacks(false) +, mDispatchingCallbacks(false) , mHasData(false) , mState(NOTLOADED) , mRegistration(NEVERREGISTERED) @@ -268,11 +282,12 @@ void CacheEntry::AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags bool truncate = aFlags & nsICacheStorage::OPEN_TRUNCATE; bool priority = aFlags & nsICacheStorage::OPEN_PRIORITY; bool multithread = aFlags & nsICacheStorage::CHECK_MULTITHREADED; + bool async = aFlags & nsICacheStorage::FORCE_ASYNC_CALLBACK; MOZ_ASSERT(!readonly || !truncate, "Bad flags combination"); MOZ_ASSERT(!(truncate && mState > LOADING), "Must not call truncate on already loaded entry"); - Callback callback(this, aCallback, readonly, multithread); + Callback callback(this, aCallback, readonly, multithread, async); mozilla::MutexAutoLock lock(mLock); @@ -509,9 +524,14 @@ void CacheEntry::RememberCallback(Callback & aCallback, bool aBypassIfBusy) mCallbacks.AppendElement(aCallback); } -void CacheEntry::InvokeCallbacksLock() +void CacheEntry::InvokeDispatchedCallbacks() { + LOG(("CacheEntry::InvokeDispatchedCallbacks [this=%p]", this)); + mozilla::MutexAutoLock lock(mLock); + + MOZ_ASSERT(mDispatchingCallbacks); + mDispatchingCallbacks = false; InvokeCallbacks(); } @@ -539,6 +559,11 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly) return false; } + if (mDispatchingCallbacks) { + LOG((" waiting for re-redispatch!")); + return false; + } + if (!mIsDoomed && (mState == WRITING || mState == REVALIDATING)) { LOG((" entry is being written/revalidated")); return false; @@ -556,10 +581,17 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly) if (NS_SUCCEEDED(rv) && !onCheckThread) { // Redispatch to the target thread nsRefPtr > event = - NS_NewRunnableMethod(this, &CacheEntry::InvokeCallbacksLock); + NS_NewRunnableMethod(this, &CacheEntry::InvokeDispatchedCallbacks); rv = mCallbacks[i].mTargetThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); if (NS_SUCCEEDED(rv)) { + // Setting this flag up prevents invocation of any callbacks until + // InvokeDispatchedCallbacks is fired on the target thread as a precaution + // of any unexpected call to InvokeCallbacks during climb back on the stack. + // E.g. GC could release a write handler that invokes callbacks immediately. + // Note: InvokeDispatchedCallbacks acquires the lock before checking/dropping + // this flag. + mDispatchingCallbacks = true; LOG((" re-dispatching to target thread")); return false; } @@ -589,6 +621,11 @@ bool CacheEntry::InvokeCallback(Callback & aCallback) mLock.AssertCurrentThreadOwns(); + if (mDispatchingCallbacks) { + LOG((" waiting for callbacks re-dispatch")); + return false; + } + // When this entry is doomed we want to notify the callback any time if (!mIsDoomed) { // When we are here, the entry must be loaded from disk diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h index e4ec3d72dbf9..a1fb32b18251 100644 --- a/netwerk/cache2/CacheEntry.h +++ b/netwerk/cache2/CacheEntry.h @@ -135,7 +135,7 @@ private: public: Callback(CacheEntry* aEntry, nsICacheEntryOpenCallback *aCallback, - bool aReadOnly, bool aCheckOnAnyThread); + bool aReadOnly, bool aCheckOnAnyThread, bool aForceAsync); Callback(Callback const &aThat); ~Callback(); @@ -153,8 +153,9 @@ private: bool mCheckOnAnyThread : 1; bool mRecheckAfterWrite : 1; bool mNotWanted : 1; + bool mForceAsync : 1; - nsresult OnCheckThread(bool *aOnCheckThread) const; + nsresult OnCheckThread(bool *aOnCheckThread); nsresult OnAvailThread(bool *aOnAvailThread) const; }; @@ -211,7 +212,7 @@ private: void OnLoaded(); void RememberCallback(Callback & aCallback, bool aBypassIfBusy); - void InvokeCallbacksLock(); + void InvokeDispatchedCallbacks(); void InvokeCallbacks(); bool InvokeCallbacks(bool aReadOnly); bool InvokeCallback(Callback & aCallback); @@ -277,8 +278,12 @@ private: // Whether security info has already been looked up in metadata. bool mSecurityInfoLoaded : 1; - // Prevents any callback invocation + // Prevents any callback invocation, used to not loop when we're recreating this entry. bool mPreventCallbacks : 1; + // Set at true between redispatch of callbacks from InvokeCallbacks and call of + // InvokeDispatchedCallbacks on the target thread. Prevents any callback invocation + // during that time. + bool mDispatchingCallbacks : 1; // true: after load and an existing file, or after output stream has been opened. // note - when opening an input stream, and this flag is false, output stream // is open along ; this makes input streams on new entries behave correctly diff --git a/netwerk/cache2/nsICacheStorage.idl b/netwerk/cache2/nsICacheStorage.idl index ca6f948b085a..d465329d52c9 100644 --- a/netwerk/cache2/nsICacheStorage.idl +++ b/netwerk/cache2/nsICacheStorage.idl @@ -50,6 +50,13 @@ interface nsICacheStorage : nsISupports */ const uint32_t CHECK_MULTITHREADED = 1 << 4; + /** + * Forces the callback to be invoked always only asynchronously regardless + * we have all the information to invoke it directly from inside asyncOpenURI + * method. + */ + const uint32_t FORCE_ASYNC_CALLBACK = 1 << 5; + /** * Asynchronously opens a cache entry for the specified URI. * Result is fetched asynchronously via the callback. @@ -69,6 +76,7 @@ interface nsICacheStorage : nsISupports * OPEN_BYPASS_IF_BUSY - backward compatibility only, LOAD_BYPASS_LOCAL_CACHE_IF_BUSY * CHECK_MULTITHREADED - onCacheEntryCheck may be called on any thread, consumer * implementation is thread-safe + * FORCE_ASYNC_CALLBACK - always call the callback asynchronously * @param aCallback * The consumer that receives the result. * IMPORTANT: The callback may be called sooner the method returns. diff --git a/netwerk/test/unit/test_cache2-01f-basic-async.js b/netwerk/test/unit/test_cache2-01f-basic-async.js new file mode 100644 index 000000000000..5cda7b5b6501 --- /dev/null +++ b/netwerk/test/unit/test_cache2-01f-basic-async.js @@ -0,0 +1,28 @@ +function run_test() +{ + do_get_profile(); + + // Open for write, write + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, + new OpenCallback(NEW, "a1m", "a1d", function(entry) { + // Open for read and check + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, + new OpenCallback(NORMAL, "a1m", "a1d", function(entry) { + // Open for rewrite (truncate), write different meta and data + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_TRUNCATE | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, + new OpenCallback(NEW, "a2m", "a2d", function(entry) { + // Open for read and check + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, + new OpenCallback(NORMAL, "a2m", "a2d", function(entry) { + finish_cache2_test(); + }) + ); + }) + ); + }) + ); + }) + ); + + do_test_pending(); +} diff --git a/netwerk/test/unit/test_cache2-24-force-async.js b/netwerk/test/unit/test_cache2-24-force-async.js new file mode 100644 index 000000000000..5cd4f153aa0f --- /dev/null +++ b/netwerk/test/unit/test_cache2-24-force-async.js @@ -0,0 +1,42 @@ +function run_test() +{ + do_get_profile(); + + // Open for write, write, and wait for finishing it before notification to avoid concurrent write + // since we want to get as much as possible the scenario when an entry is left in the pool + // and a new consumer comes to open it later. + var outOfAsyncOpen0 = false; + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, + new OpenCallback(NEW|WAITFORWRITE, "a1m", "a1d", function(entry) { + do_check_true(outOfAsyncOpen0); + // Open for read, expect callback happen from inside asyncOpenURI + var outOfAsyncOpen1 = false; + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null, + function(entry) { + do_check_false(outOfAsyncOpen1); + var outOfAsyncOpen2 = false; + // Open for read, again should be sync + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null, + function(entry) { + do_check_false(outOfAsyncOpen2); + var outOfAsyncOpen3 = false; + // Open for read, expect callback happen from outside of asyncOpenURI + asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, + function(entry) { + do_check_true(outOfAsyncOpen3); + finish_cache2_test(); + } + ); + outOfAsyncOpen3 = true; + } + ); + outOfAsyncOpen2 = true; + } + ); + outOfAsyncOpen1 = true; + }) + ); + outOfAsyncOpen0 = true; + + do_test_pending(); +} diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index 33e637bcf9e6..9f50f94147bb 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -25,6 +25,7 @@ support-files = [test_cache2-01c-basic-hasmeta-only.js] [test_cache2-01d-basic-not-wanted.js] [test_cache2-01e-basic-bypass-if-busy.js] +[test_cache2-01f-basic-async.js] [test_cache2-02-open-non-existing.js] [test_cache2-03-oncacheentryavail-throws.js] [test_cache2-04-oncacheentryavail-throws2x.js] @@ -57,6 +58,7 @@ skip-if = os == "android" [test_cache2-21-anon-storage.js] [test_cache2-22-anon-visit.js] [test_cache2-23-read-over-chunk.js] +[test_cache2-24-force-async.js] [test_304_responses.js] # Bug 675039: test hangs on Android-armv6 skip-if = os == "android" From 678d3c183c1895b6103af805d9381f1893f09b4f Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 6 Jun 2014 14:54:35 +0200 Subject: [PATCH 20/52] Bug 1018085 - "ASSERTION: Inner window supports nsWrapperCache, fix WrapObject!". r=bz --HG-- extra : rebase_source : f988ef0d99419ac66064a03beaa51f4d2215f146 --- dom/base/nsGlobalWindow.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 314d2ca44351..dbbe2cffa1c3 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -350,9 +350,7 @@ public: // nsWrapperCache virtual JSObject *WrapObject(JSContext *cx) MOZ_OVERRIDE { - NS_ASSERTION(IsOuterWindow(), - "Inner window supports nsWrapperCache, fix WrapObject!"); - return EnsureInnerWindow() ? GetWrapper() : nullptr; + return IsInnerWindow() || EnsureInnerWindow() ? GetWrapper() : nullptr; } // nsIGlobalJSObjectHolder From e9ce83973af7cc128fb532340f40a3db668e6c98 Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Mon, 9 Jun 2014 12:28:41 -0700 Subject: [PATCH 21/52] Bug 978229 - Remove now unused NormalizeAndCompletePropertyDescriptor(). (r=Waldo) --- js/src/jsproxy.cpp | 72 ---------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 027f0fddf8f1..568ce7e31ff9 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -1111,78 +1111,6 @@ FromGenericPropertyDescriptor(JSContext *cx, MutableHandle desc, Mutab return true; } -/* - * Aux.3 NormalizePropertyDescriptor(Attributes) - * - * NOTE: to minimize code duplication, the code for this function is shared with - * that for Aux.4 NormalizeAndCompletePropertyDescriptor (see below). The - * argument complete is used to distinguish between the two. - */ -static bool -NormalizePropertyDescriptor(JSContext *cx, MutableHandleValue vp, bool complete = false) -{ - // Aux.4 step 1 - if (complete && vp.isUndefined()) - return true; - - // Aux.3 steps 1-2 / Aux.4 steps 2-3 - Rooted desc(cx); - if (!desc.initialize(cx, vp.get())) - return false; - if (complete) - desc.complete(); - JS_ASSERT(vp.isObject()); // due to desc->initialize - RootedObject attributes(cx, &vp.toObject()); - - /* - * Aux.3 step 3 / Aux.4 step 4 - * - * NOTE: Aux.4 step 4 actually specifies FromPropertyDescriptor here. - * However, the way FromPropertyDescriptor is implemented (PropDesc:: - * makeObject) is actually closer to FromGenericPropertyDescriptor, - * and is in fact used to implement the latter, so we might as well call it - * directly. - */ - if (!FromGenericPropertyDescriptor(cx, &desc, vp)) - return false; - if (vp.isUndefined()) - return true; - RootedObject descObj(cx, &vp.toObject()); - - // Aux.3 steps 4-5 / Aux.4 steps 5-6 - AutoIdVector props(cx); - if (!GetPropertyNames(cx, attributes, 0, &props)) - return false; - size_t n = props.length(); - for (size_t i = 0; i < n; ++i) { - RootedId id(cx, props[i]); - if (JSID_IS_ATOM(id)) { - JSAtom *atom = JSID_TO_ATOM(id); - const JSAtomState &atomState = cx->names(); - if (atom == atomState.value || atom == atomState.writable || - atom == atomState.get || atom == atomState.set || - atom == atomState.enumerable || atom == atomState.configurable) - { - continue; - } - } - - RootedValue v(cx); - if (!JSObject::getGeneric(cx, descObj, attributes, id, &v)) - return false; - if (!JSObject::defineGeneric(cx, descObj, id, v, nullptr, nullptr, JSPROP_ENUMERATE)) - return false; - } - return true; -} - -// Aux.4 NormalizeAndCompletePropertyDescriptor(Attributes) -static inline bool -NormalizeAndCompletePropertyDescriptor(JSContext *cx, MutableHandleValue vp) -{ - return NormalizePropertyDescriptor(cx, vp, true); -} - static inline bool IsDataDescriptor(const PropertyDescriptor &desc) { From 834b7d91b5dd6994c3340cb2d49b2fe648bfe091 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 9 Jun 2014 15:30:01 -0400 Subject: [PATCH 22/52] Backed out changeset 3b877866e65c (bug 1022235) since it just pushed the crashes to the next test. --- dom/src/offline/crashtests/crashtests.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/src/offline/crashtests/crashtests.list b/dom/src/offline/crashtests/crashtests.list index 39d23a72d734..a185168c2634 100644 --- a/dom/src/offline/crashtests/crashtests.list +++ b/dom/src/offline/crashtests/crashtests.list @@ -1 +1 @@ -skip load 408431-1.html # bug 1022509 - renable when the cause of that is backed out +load 408431-1.html From 125c1f6b7180058a44d7915ce60b8eb9e56e2868 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sun, 8 Jun 2014 22:35:44 -0400 Subject: [PATCH 23/52] Bug 996492 - Remove unused globalReport.errors. r=bwc --- toolkit/content/aboutWebrtc.xhtml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/toolkit/content/aboutWebrtc.xhtml b/toolkit/content/aboutWebrtc.xhtml index b8d99a6d3e52..ff23f6e1cd5a 100644 --- a/toolkit/content/aboutWebrtc.xhtml +++ b/toolkit/content/aboutWebrtc.xhtml @@ -368,20 +368,6 @@ function displayStats(globalReport) { document.getElementById('stats').replaceChild(newPcDiv, pcDiv); } }); - - globalReport.errors.forEach(function (error) { - var pcDivHeading = 'PeerConnection:' + error.pcid; - - var pcDiv = document.getElementById(pcDivHeading); - var newPcDiv = buildPcDiv(error, pcDivHeading); - newPcDiv.id = pcDivHeading; - - if (pcDiv) { - document.getElementById('stats').replaceChild(newPcDiv, pcDiv); - } else { - document.getElementById('stats').appendChild(newPcDiv); - } - }); } function onLoad() { From f7fd2e76e3cb8524a073174e05549bd6d6fececa Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Mon, 9 Jun 2014 06:25:00 -0400 Subject: [PATCH 24/52] Bug 1011158 - Tighten the lock around OS.File |kill| operation. r=froydnj --- .../osfile/modules/osfile_async_front.jsm | 19 ++++++++-- .../osfile/tests/xpcshell/test_reset.js | 35 +++++++++++++------ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/toolkit/components/osfile/modules/osfile_async_front.jsm b/toolkit/components/osfile/modules/osfile_async_front.jsm index 28881ccd8be1..2dc92c0b9fd9 100644 --- a/toolkit/components/osfile/modules/osfile_async_front.jsm +++ b/toolkit/components/osfile/modules/osfile_async_front.jsm @@ -192,12 +192,20 @@ let Scheduler = { shutdown: false, /** - * A promise resolved once all operations are complete. + * A promise resolved once all currently pending operations are complete. * * This promise is never rejected and the result is always undefined. */ queue: Promise.resolve(), + /** + * A promise resolved once all currently pending `kill` operations + * are complete. + * + * This promise is never rejected and the result is always undefined. + */ + _killQueue: Promise.resolve(), + /** * Miscellaneous debugging information */ @@ -286,7 +294,14 @@ let Scheduler = { * through some other mean. */ kill: function({shutdown, reset}) { - return Task.spawn(function*() { + // Grab the kill queue to make sure that we + // cannot be interrupted by another call to `kill`. + let killQueue = this._killQueue; + return this._killQueue = Task.spawn(function*() { + + yield killQueue; + // From this point, and until the end of the Task, we are the + // only call to `kill`, regardless of any `yield`. yield this.queue; diff --git a/toolkit/components/osfile/tests/xpcshell/test_reset.js b/toolkit/components/osfile/tests/xpcshell/test_reset.js index 9c4cc6a82ec5..ce56bb63b5ec 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_reset.js +++ b/toolkit/components/osfile/tests/xpcshell/test_reset.js @@ -1,20 +1,18 @@ -Components.utils.import("resource://gre/modules/Services.jsm", this); -Components.utils.import("resource://gre/modules/Promise.jsm", this); -Components.utils.import("resource://gre/modules/Task.jsm", this); -Components.utils.import("resource://gre/modules/osfile.jsm", this); +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ let Path = OS.Constants.Path; -add_task(function init() { +add_task(function* init() { do_get_profile(); }); -add_task(function reset_before_launching() { +add_task(function* reset_before_launching() { do_print("Reset without launching OS.File, it shouldn't break"); yield OS.File.resetWorker(); }); -add_task(function transparent_reset() { +add_task(function* transparent_reset() { for (let i = 1; i < 3; ++i) { do_print("Do stome stuff before and after " + i + " reset(s), " + "it shouldn't break"); @@ -30,7 +28,7 @@ add_task(function transparent_reset() { } }); -add_task(function file_open_cannot_reset() { +add_task(function* file_open_cannot_reset() { let TEST_FILE = OS.Path.join(Path.profileDir, "tmp-" + Math.random()); do_print("Leaking file descriptor " + TEST_FILE + ", we shouldn't be able to reset"); let openedFile = yield OS.File.open(TEST_FILE, { create: true} ); @@ -47,7 +45,7 @@ add_task(function file_open_cannot_reset() { yield OS.File.resetWorker(); }); -add_task(function dir_open_cannot_reset() { +add_task(function* dir_open_cannot_reset() { let TEST_DIR = yield OS.File.getCurrentDirectory(); do_print("Leaking directory " + TEST_DIR + ", we shouldn't be able to reset"); let iterator = new OS.File.DirectoryIterator(TEST_DIR); @@ -64,7 +62,24 @@ add_task(function dir_open_cannot_reset() { yield OS.File.resetWorker(); }); -add_task(function finish_with_a_reset() { +add_task(function* race_against_itself() { + do_print("Attempt to get resetWorker() to race against itself"); + // Arbitrary operation, just to wake up the worker + try { + yield OS.File.read("/foo"); + } catch (ex) { + } + + let all = []; + for (let i = 0; i < 100; ++i) { + all.push(OS.File.resetWorker()); + } + + yield Promise.all(all); +}); + + +add_task(function* finish_with_a_reset() { do_print("Reset without waiting for the result"); // Arbitrary operation, just to wake up the worker try { From 039b13df10b672381e111d028abd003057fe1927 Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Mon, 9 Jun 2014 12:07:00 -0400 Subject: [PATCH 25/52] Bug 1017706 - Make sure that healthreporter.jsm always initiates shutdown, even if it never receives quit-application. r=gps --- services/healthreport/healthreporter.jsm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/services/healthreport/healthreporter.jsm b/services/healthreport/healthreporter.jsm index f33bf4f34792..e7ebf93bc3dc 100644 --- a/services/healthreport/healthreporter.jsm +++ b/services/healthreport/healthreporter.jsm @@ -402,7 +402,15 @@ AbstractHealthReporter.prototype = Object.freeze({ // The database needs to be shut down by the end of shutdown // phase profileBeforeChange. Metrics.Storage.shutdown.addBlocker("FHR: Flushing storage shutdown", - this._promiseShutdown, + () => { + // Workaround bug 1017706 + // Apparently, in some cases, quit-application is not triggered + // (or is triggered after profile-before-change), so we need to + // make sure that `_initiateShutdown()` is triggered at least + // once. + this._initiateShutdown(); + return this._promiseShutdown; + }, () => ({ shutdownInitiated: this._shutdownInitiated, initialized: this._initialized, @@ -412,7 +420,7 @@ AbstractHealthReporter.prototype = Object.freeze({ storageInProgress: this._storageInProgress, hasProviderManager: !!this._providerManager, hasStorage: !!this._storage, - shutdownComplete: this.shutdownComplete + shutdownComplete: this._shutdownComplete })); try { From 088c6fc4432ead9df75377c7f20cbf50d0205f12 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Fri, 6 Jun 2014 09:39:11 +0200 Subject: [PATCH 26/52] Bug 1018686 - Fix latent NPE in Nursery.cpp. r=jonco --- js/src/gc/Nursery.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 9fe83e76d533..bd4c372ca3c2 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -244,7 +244,7 @@ js::Nursery::reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots, if (!isInside(oldSlots)) { HeapSlot *newSlots = static_cast(cx->realloc_(oldSlots, oldSize, newSize)); - if (oldSlots != newSlots) { + if (newSlots && oldSlots != newSlots) { hugeSlots.remove(oldSlots); /* If this put fails, we will only leak the slots. */ (void)hugeSlots.put(newSlots); @@ -257,7 +257,8 @@ js::Nursery::reallocateSlots(JSContext *cx, JSObject *obj, HeapSlot *oldSlots, return oldSlots; HeapSlot *newSlots = allocateSlots(cx, obj, newCount); - PodCopy(newSlots, oldSlots, oldCount); + if (newSlots) + PodCopy(newSlots, oldSlots, oldCount); return newSlots; } @@ -284,7 +285,8 @@ js::Nursery::allocateHugeSlots(JSContext *cx, size_t nslots) { HeapSlot *slots = cx->pod_malloc(nslots); /* If this put fails, we will only leak the slots. */ - (void)hugeSlots.put(slots); + if (slots) + (void)hugeSlots.put(slots); return slots; } From 94dcca9b50fe9e2e129f6d929411e540cf7336be Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 9 Jun 2014 12:30:38 -0700 Subject: [PATCH 27/52] Bug 1016738 - Back out for webrtc crashes. --- js/public/GCAPI.h | 2 +- js/src/gc/Marking.cpp | 32 +------ js/src/gc/Tracer.cpp | 15 +--- js/src/gc/Zone.cpp | 2 + js/src/gc/Zone.h | 5 ++ js/src/jsapi.cpp | 1 + js/src/jscompartment.cpp | 4 +- js/src/jscompartment.h | 5 -- js/src/jsfriendapi.cpp | 8 +- js/src/jsgc.cpp | 119 +++++++++++++------------- js/src/jsgcinlines.h | 27 ++++++ js/src/jsobj.cpp | 3 + js/src/jswrapper.cpp | 4 + js/src/jswrapper.h | 28 ++++++ js/src/vm/Debugger.cpp | 4 +- js/src/vm/ProxyObject.cpp | 9 +- js/xpconnect/src/XPCWrappedNative.cpp | 6 ++ 17 files changed, 158 insertions(+), 116 deletions(-) diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index 197d23fd8c16..5924d79c13dd 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -45,7 +45,7 @@ namespace JS { D(TOO_MUCH_MALLOC) \ D(ALLOC_TRIGGER) \ D(DEBUG_GC) \ - D(COMPARTMENT_REVIVED) \ + D(TRANSPLANT) \ D(RESET) \ D(OUT_OF_NURSERY) \ D(EVICT_NURSERY) \ diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index b5b93080b8fb..e76113539826 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -188,6 +188,9 @@ CheckMarkedThing(JSTracer *trc, T **thingp) DebugOnly rt = trc->runtime(); + JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gc.manipulatingDeadZones, + !thing->zone()->scheduledForDestruction); + JS_ASSERT(CurrentThreadCanAccessRuntime(rt)); JS_ASSERT_IF(thing->zone()->requireGCTracer(), @@ -218,33 +221,6 @@ CheckMarkedThing(JSTracer *trc, T **thingp) } -/* - * We only set the maybeAlive flag for objects and scripts. It's assumed that, - * if a compartment is alive, then it will have at least some live object or - * script it in. Even if we get this wrong, the worst that will happen is that - * scheduledForDestruction will be set on the compartment, which will cause some - * extra GC activity to try to free the compartment. - */ -template -static inline void -SetMaybeAliveFlag(T *thing) -{ -} - -template<> -void -SetMaybeAliveFlag(JSObject *thing) -{ - thing->compartment()->maybeAlive = true; -} - -template<> -void -SetMaybeAliveFlag(JSScript *thing) -{ - thing->compartment()->maybeAlive = true; -} - template static void MarkInternal(JSTracer *trc, T **thingp) @@ -278,7 +254,7 @@ MarkInternal(JSTracer *trc, T **thingp) return; PushMarkStack(AsGCMarker(trc), thing); - SetMaybeAliveFlag(thing); + thing->zone()->maybeAlive = true; } else { trc->callback(trc, (void **)thingp, MapTypeToTraceKind::kind); trc->unsetTracingLocation(); diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index e029182af698..18692ba175a3 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -638,20 +638,7 @@ GCMarker::appendGrayRoot(void *thing, JSGCTraceKind kind) Zone *zone = static_cast(thing)->tenuredZone(); if (zone->isCollecting()) { - // See the comment on SetMaybeAliveFlag to see why we only do this for - // objects and scripts. We rely on gray root buffering for this to work, - // but we only need to worry about uncollected dead compartments during - // incremental GCs (when we do gray root buffering). - switch (kind) { - case JSTRACE_OBJECT: - static_cast(thing)->compartment()->maybeAlive = true; - break; - case JSTRACE_SCRIPT: - static_cast(thing)->compartment()->maybeAlive = true; - break; - default: - break; - } + zone->maybeAlive = true; if (!zone->gcGrayRoots.append(root)) { resetBufferedGrayRoots(); grayBufferState = GRAY_BUFFER_FAILED; diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index efa6e9cb699f..9cc5e244bb2a 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -35,6 +35,8 @@ JS::Zone::Zone(JSRuntime *rt) data(nullptr), isSystem(false), usedByExclusiveThread(false), + scheduledForDestruction(false), + maybeAlive(true), active(false), jitZone_(nullptr), gcState_(NoGC), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 6cbf0f4ad9e3..648f3194a09d 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -258,6 +258,11 @@ struct Zone : public JS::shadow::Zone, bool usedByExclusiveThread; + // These flags help us to discover if a compartment that shouldn't be alive + // manages to outlive a GC. + bool scheduledForDestruction; + bool maybeAlive; + // True when there are active frames. bool active; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index c4117b822270..3192f876976e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1090,6 +1090,7 @@ JS_TransplantObject(JSContext *cx, HandleObject origobj, HandleObject target) JS_ASSERT(!origobj->is()); JS_ASSERT(!target->is()); + AutoMaybeTouchDeadZones agc(cx); AutoDisableProxyCheck adpc(cx->runtime()); JSCompartment *destination = target->compartment(); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 0cbb19d92374..c2313360e71f 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -65,9 +65,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options = debugScriptMap(nullptr), debugScopes(nullptr), enumerators(nullptr), - compartmentStats(nullptr), - scheduledForDestruction(false), - maybeAlive(true) + compartmentStats(nullptr) #ifdef JS_ION , jitCompartment_(nullptr) #endif diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index a99325cd5395..6a296540c9b6 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -448,11 +448,6 @@ struct JSCompartment /* Used by memory reporters and invalid otherwise. */ void *compartmentStats; - // These flags help us to discover if a compartment that shouldn't be alive - // manages to outlive a GC. - bool scheduledForDestruction; - bool maybeAlive; - #ifdef JS_ION private: js::jit::JitCompartment *jitCompartment_; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index ef752cfc7c35..a198f499fd1e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -978,6 +978,8 @@ JS::IncrementalObjectBarrier(JSObject *obj) JS_ASSERT(!obj->zone()->runtimeFromMainThread()->isHeapMajorCollecting()); + AutoMarkInDeadZone amn(obj->zone()); + JSObject::writeBarrierPre(obj); } @@ -988,13 +990,13 @@ JS::IncrementalReferenceBarrier(void *ptr, JSGCTraceKind kind) return; gc::Cell *cell = static_cast(ptr); - -#ifdef DEBUG Zone *zone = kind == JSTRACE_OBJECT ? static_cast(cell)->zone() : cell->tenuredZone(); + JS_ASSERT(!zone->runtimeFromMainThread()->isHeapMajorCollecting()); -#endif + + AutoMarkInDeadZone amn(zone); if (kind == JSTRACE_OBJECT) JSObject::writeBarrierPre(static_cast(cell)); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 9c7e37752f97..dd085edd128d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2984,14 +2984,14 @@ GCRuntime::beginMarkPhase() isFull = false; } + zone->scheduledForDestruction = false; + zone->maybeAlive = false; zone->setPreservingCode(false); } for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) { JS_ASSERT(c->gcLiveArrayBuffers.empty()); c->marked = false; - c->scheduledForDestruction = false; - c->maybeAlive = false; if (shouldPreserveJITCode(c, currentTime)) c->zone()->setPreservingCode(true); } @@ -3092,50 +3092,40 @@ GCRuntime::beginMarkPhase() bufferGrayRoots(); /* - * This code ensures that if a compartment is "dead", then it will be - * collected in this GC. A compartment is considered dead if its maybeAlive + * This code ensures that if a zone is "dead", then it will be + * collected in this GC. A zone is considered dead if its maybeAlive * flag is false. The maybeAlive flag is set if: - * (1) the compartment has incoming cross-compartment edges, or - * (2) an object in the compartment was marked during root marking, either + * (1) the zone has incoming cross-compartment edges, or + * (2) an object in the zone was marked during root marking, either * as a black root or a gray root. * If the maybeAlive is false, then we set the scheduledForDestruction flag. - * At the end of the GC, we look for compartments where - * scheduledForDestruction is true. These are compartments that were somehow - * "revived" during the incremental GC. If any are found, we do a special, - * non-incremental GC of those compartments to try to collect them. + * At any time later in the GC, if we try to mark an object whose + * zone is scheduled for destruction, we will assert. + * NOTE: Due to bug 811587, we only assert if gcManipulatingDeadCompartments + * is true (e.g., if we're doing a brain transplant). * - * Compartments can be revived for a variety of reasons. On reason is bug - * 811587, where a reflector that was dead can be revived by DOM code that - * still refers to the underlying DOM node. + * The purpose of this check is to ensure that a zone that we would + * normally destroy is not resurrected by a read barrier or an + * allocation. This might happen during a function like JS_TransplantObject, + * which iterates over all compartments, live or dead, and operates on their + * objects. See bug 803376 for details on this problem. To avoid the + * problem, we are very careful to avoid allocation and read barriers during + * JS_TransplantObject and the like. The code here ensures that we don't + * regress. * - * Read barriers and allocations can also cause revival. This might happen - * during a function like JS_TransplantObject, which iterates over all - * compartments, live or dead, and operates on their objects. See bug 803376 - * for details on this problem. To avoid the problem, we try to avoid - * allocation and read barriers during JS_TransplantObject and the like. + * Note that there are certain cases where allocations or read barriers in + * dead zone are difficult to avoid. We detect such cases (via the + * gcObjectsMarkedInDeadCompartment counter) and redo any ongoing GCs after + * the JS_TransplantObject function has finished. This ensures that the dead + * zones will be cleaned up. See AutoMarkInDeadZone and + * AutoMaybeTouchDeadZones for details. */ /* Set the maybeAlive flag based on cross-compartment edges. */ for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) { - const CrossCompartmentKey &key = e.front().key(); - JSCompartment *dest; - switch (key.kind) { - case CrossCompartmentKey::ObjectWrapper: - case CrossCompartmentKey::DebuggerObject: - case CrossCompartmentKey::DebuggerSource: - case CrossCompartmentKey::DebuggerEnvironment: - dest = static_cast(key.wrapped)->compartment(); - break; - case CrossCompartmentKey::DebuggerScript: - dest = static_cast(key.wrapped)->compartment(); - break; - default: - dest = nullptr; - break; - } - if (dest) - dest->maybeAlive = true; + Cell *dst = e.front().key().wrapped; + dst->tenuredZone()->maybeAlive = true; } } @@ -3144,9 +3134,9 @@ GCRuntime::beginMarkPhase() * during MarkRuntime. */ - for (GCCompartmentsIter c(rt); !c.done(); c.next()) { - if (!c->maybeAlive && !rt->isAtomsCompartment(c)) - c->scheduledForDestruction = true; + for (GCZonesIter zone(rt); !zone.done(); zone.next()) { + if (!zone->maybeAlive && !rt->isAtomsZone(zone)) + zone->scheduledForDestruction = true; } foundBlackGrayEdges = false; @@ -4522,8 +4512,8 @@ GCRuntime::resetIncrementalGC(const char *reason) case SWEEP: marker.reset(); - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) - c->scheduledForDestruction = false; + for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) + zone->scheduledForDestruction = false; /* Finish sweeping the current zone group, then abort. */ abortSweepAfterCurrentGroup = true; @@ -5001,30 +4991,13 @@ GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind, if (poked && shouldCleanUpEverything) JS::PrepareForFullGC(rt); - /* - * This code makes an extra effort to collect compartments that we - * thought were dead at the start of the GC. See the large comment in - * beginMarkPhase. - */ - bool repeatForDeadZone = false; - if (incremental && incrementalState == NO_INCREMENTAL) { - for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { - if (c->scheduledForDestruction) { - incremental = false; - repeatForDeadZone = true; - reason = JS::gcreason::COMPARTMENT_REVIVED; - c->zone()->scheduleGC(); - } - } - } - /* * If we reset an existing GC, we need to start a new one. Also, we * repeat GCs that happen during shutdown (the gcShouldCleanUpEverything * case) until we can be sure that no additional garbage is created * (which typically happens if roots are dropped during finalizers). */ - repeat = (poked && shouldCleanUpEverything) || wasReset || repeatForDeadZone; + repeat = (poked && shouldCleanUpEverything) || wasReset; } while (repeat); if (incrementalState == NO_INCREMENTAL) { @@ -5561,6 +5534,34 @@ ArenaLists::containsArena(JSRuntime *rt, ArenaHeader *needle) } +AutoMaybeTouchDeadZones::AutoMaybeTouchDeadZones(JSContext *cx) + : runtime(cx->runtime()), + markCount(runtime->gc.objectsMarkedInDeadZones), + inIncremental(JS::IsIncrementalGCInProgress(runtime)), + manipulatingDeadZones(runtime->gc.manipulatingDeadZones) +{ + runtime->gc.manipulatingDeadZones = true; +} + +AutoMaybeTouchDeadZones::AutoMaybeTouchDeadZones(JSObject *obj) + : runtime(obj->compartment()->runtimeFromMainThread()), + markCount(runtime->gc.objectsMarkedInDeadZones), + inIncremental(JS::IsIncrementalGCInProgress(runtime)), + manipulatingDeadZones(runtime->gc.manipulatingDeadZones) +{ + runtime->gc.manipulatingDeadZones = true; +} + +AutoMaybeTouchDeadZones::~AutoMaybeTouchDeadZones() +{ + runtime->gc.manipulatingDeadZones = manipulatingDeadZones; + + if (inIncremental && runtime->gc.objectsMarkedInDeadZones != markCount) { + JS::PrepareForFullGC(runtime); + js::GC(runtime, GC_NORMAL, JS::gcreason::TRANSPLANT); + } +} + AutoSuppressGC::AutoSuppressGC(ExclusiveContext *cx) : suppressGC_(cx->perThreadData->suppressGC) { diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 580fe0bdf02e..7c79586ecf57 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -15,6 +15,33 @@ namespace js { class Shape; +/* + * This auto class should be used around any code that might cause a mark bit to + * be set on an object in a dead zone. See AutoMaybeTouchDeadZones + * for more details. + */ +struct AutoMarkInDeadZone +{ + explicit AutoMarkInDeadZone(JS::Zone *zone) + : zone(zone), + scheduled(zone->scheduledForDestruction) + { + JSRuntime *rt = zone->runtimeFromMainThread(); + if (rt->gc.manipulatingDeadZones && zone->scheduledForDestruction) { + rt->gc.objectsMarkedInDeadZones++; + zone->scheduledForDestruction = false; + } + } + + ~AutoMarkInDeadZone() { + zone->scheduledForDestruction = scheduled; + } + + private: + JS::Zone *zone; + bool scheduled; +}; + inline Allocator * ThreadSafeContext::allocator() const { diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 087bda2ab9fd..ef2e50fa2fde 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2505,6 +2505,9 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & bool JSObject::swap(JSContext *cx, HandleObject a, HandleObject b) { + AutoMarkInDeadZone adc1(a->zone()); + AutoMarkInDeadZone adc2(b->zone()); + // Ensure swap doesn't cause a finalizer to not be run. JS_ASSERT(IsBackgroundFinalized(a->tenuredGetAllocKind()) == IsBackgroundFinalized(b->tenuredGetAllocKind())); diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 31d1c7aab04b..e5e3b706d7bc 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -44,6 +44,8 @@ Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, Wrapper *handler, { JS_ASSERT(parent); + AutoMarkInDeadZone amd(cx->zone()); + RootedValue priv(cx, ObjectValue(*obj)); mozilla::Maybe opts; if (!options) { @@ -1043,6 +1045,8 @@ JS_FRIEND_API(bool) js::RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter, const CompartmentFilter &targetFilter) { + AutoMaybeTouchDeadZones agc(cx); + AutoWrapperVector toRecompute(cx); for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) { diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 1aace7702c3a..ec67447f8e1a 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -304,6 +304,34 @@ JS_FRIEND_API(bool) RecomputeWrappers(JSContext *cx, const CompartmentFilter &sourceFilter, const CompartmentFilter &targetFilter); +/* + * This auto class should be used around any code, such as brain transplants, + * that may touch dead zones. Brain transplants can cause problems + * because they operate on all compartments, whether live or dead. A brain + * transplant can cause a formerly dead object to be "reanimated" by causing a + * read or write barrier to be invoked on it during the transplant. In this way, + * a zone becomes a zombie, kept alive by repeatedly consuming + * (transplanted) brains. + * + * To work around this issue, we observe when mark bits are set on objects in + * dead zones. If this happens during a brain transplant, we do a full, + * non-incremental GC at the end of the brain transplant. This will clean up any + * objects that were improperly marked. + */ +struct JS_FRIEND_API(AutoMaybeTouchDeadZones) +{ + // The version that takes an object just uses it for its runtime. + explicit AutoMaybeTouchDeadZones(JSContext *cx); + explicit AutoMaybeTouchDeadZones(JSObject *obj); + ~AutoMaybeTouchDeadZones(); + + private: + JSRuntime *runtime; + unsigned markCount; + bool inIncremental; + bool manipulatingDeadZones; +}; + } /* namespace js */ #endif /* jswrapper_h */ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index c7edc4d5eb16..42b794dcbfcd 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2093,7 +2093,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp) for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { if (c == dbg->object->compartment() || c->options().invisibleToDebugger()) continue; - c->scheduledForDestruction = false; + c->zone()->scheduledForDestruction = false; GlobalObject *global = c->maybeGlobal(); if (global) { Rooted rg(cx, global); @@ -2890,7 +2890,7 @@ Debugger::findAllGlobals(JSContext *cx, unsigned argc, Value *vp) if (c->options().invisibleToDebugger()) continue; - c->scheduledForDestruction = false; + c->zone()->scheduledForDestruction = false; GlobalObject *global = c->maybeGlobal(); diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp index 384852dc93d9..e8521ee7647a 100644 --- a/js/src/vm/ProxyObject.cpp +++ b/js/src/vm/ProxyObject.cpp @@ -77,7 +77,14 @@ ProxyObject::initHandler(BaseProxyHandler *handler) static void NukeSlot(ProxyObject *proxy, uint32_t slot) { - proxy->setReservedSlot(slot, NullValue()); + Value old = proxy->getSlot(slot); + if (old.isMarkable()) { + Zone *zone = ZoneOfValue(old); + AutoMarkInDeadZone amd(zone); + proxy->setReservedSlot(slot, NullValue()); + } else { + proxy->setReservedSlot(slot, NullValue()); + } } void diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 01a147d8c186..f3e2238c9cf1 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -356,6 +356,9 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper, mozilla::Maybe ac; if (sciWrapper.GetFlags().WantPreCreate()) { + // PreCreate may touch dead compartments. + js::AutoMaybeTouchDeadZones agc(parent); + RootedObject plannedParent(cx, parent); nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, cx, parent, parent.address()); @@ -1282,6 +1285,9 @@ RescueOrphans(HandleObject obj) return NS_OK; // Global object. We're done. parentObj = js::UncheckedUnwrap(parentObj, /* stopAtOuter = */ false); + // PreCreate may touch dead compartments. + js::AutoMaybeTouchDeadZones agc(parentObj); + // Recursively fix up orphans on the parent chain. rv = RescueOrphans(parentObj); NS_ENSURE_SUCCESS(rv, rv); From c37ab000b0e6792f3106137effe5b5c88ddf12e3 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 9 Jun 2014 13:37:21 -0400 Subject: [PATCH 28/52] Bug 1022785 - disable android snippets for reftests/crashtests/jsreftests; r=jmaher --- js/src/tests/user.js | 2 ++ layout/tools/reftest/runreftest.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/js/src/tests/user.js b/js/src/tests/user.js index f3dc232e2fb3..7b9f9a054579 100755 --- a/js/src/tests/user.js +++ b/js/src/tests/user.js @@ -25,3 +25,5 @@ user_pref("security.turn_off_all_security_so_that_viruses_can_take_over_this_com user_pref("toolkit.telemetry.enabled", false); user_pref("browser.safebrowsing.enabled", false); user_pref("browser.safebrowsing.malware.enabled", false); +user_pref("browser.snippets.enabled", false); +user_pref("browser.snippets.syncPromo.enabled", false); diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index d6e903e3023f..0e1dfc8c61ad 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -171,6 +171,9 @@ class RefTest(object): # Likewise for safebrowsing. prefs['browser.safebrowsing.enabled'] = False prefs['browser.safebrowsing.malware.enabled'] = False + # And for snippets. + prefs['browser.snippets.enabled'] = False + prefs['browser.snippets.syncPromo.enabled'] = False if options.e10s: prefs['browser.tabs.remote.autostart'] = True From b97a645006087a62b38f4f78efe1719e3be38682 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 9 Jun 2014 22:11:00 +0200 Subject: [PATCH 29/52] Bug 1022739: Unbreak |mach bootstrap| with recent FreeBSD packages. r=gps --- python/mozboot/mozboot/freebsd.py | 40 +++++++++++++------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/python/mozboot/mozboot/freebsd.py b/python/mozboot/mozboot/freebsd.py index 1ac71b884854..30884a5b2660 100644 --- a/python/mozboot/mozboot/freebsd.py +++ b/python/mozboot/mozboot/freebsd.py @@ -2,12 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. -from __future__ import print_function - -import os -import subprocess -import sys - from mozboot.base import BaseBootstrapper class FreeBSDBootstrapper(BaseBootstrapper): @@ -16,33 +10,31 @@ class FreeBSDBootstrapper(BaseBootstrapper): self.version = int(version.split('.')[0]) self.packages = [ - ('autoconf-2.13', 'autoconf213'), - ('dbus-glib',), - ('gmake',), - ('gstreamer-plugins',), - ('gtk-2', 'gtk20'), - ('libGL',), - ('libIDL',), - ('libv4l',), - ('mercurial',), - ('pulseaudio',), - ('yasm',), - ('zip',), + 'autoconf213', + 'dbus-glib', + 'gmake', + 'gstreamer-plugins', + 'gtk2', + 'libGL', + 'mercurial', + 'pkgconf', + 'pulseaudio', + 'v4l_compat', + 'yasm', + 'zip', ] - # using clang since 9.0 + # gcc in base is too old if self.version < 9: - self.packages.append(('gcc',)) - + self.packages.append('gcc') def pkg_install(self, *packages): if self.which('pkg'): - command = ['pkg', 'install', '-x'] - command.extend([i[0] for i in packages]) + command = ['pkg', 'install'] else: command = ['pkg_add', '-Fr'] - command.extend([i[-1] for i in packages]) + command.extend(packages) self.run_as_root(command) def install_system_packages(self): From 9154f50eac6a4cf37da60a8e70b1cafeb0a8043b Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 9 Jun 2014 22:11:06 +0200 Subject: [PATCH 30/52] Bug 1022747: Add |mach bootstrap| support for DragonFly/DPorts. r=gps --- python/mozboot/mozboot/bootstrap.py | 4 +++- python/mozboot/mozboot/freebsd.py | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/python/mozboot/mozboot/bootstrap.py b/python/mozboot/mozboot/bootstrap.py index 8e774ac47d75..bbc84a6ae720 100644 --- a/python/mozboot/mozboot/bootstrap.py +++ b/python/mozboot/mozboot/bootstrap.py @@ -79,9 +79,11 @@ class Bootstrapper(object): cls = OpenBSDBootstrapper args['version'] = platform.uname()[2] - elif sys.platform.startswith('freebsd'): + elif sys.platform.startswith('dragonfly') or \ + sys.platform.startswith('freebsd'): cls = FreeBSDBootstrapper args['version'] = platform.release() + args['flavor'] = platform.system() if cls is None: raise NotImplementedError('Bootstrap support is not yet available ' diff --git a/python/mozboot/mozboot/freebsd.py b/python/mozboot/mozboot/freebsd.py index 30884a5b2660..b908944d8899 100644 --- a/python/mozboot/mozboot/freebsd.py +++ b/python/mozboot/mozboot/freebsd.py @@ -5,9 +5,10 @@ from mozboot.base import BaseBootstrapper class FreeBSDBootstrapper(BaseBootstrapper): - def __init__(self, version): + def __init__(self, version, flavor): BaseBootstrapper.__init__(self) self.version = int(version.split('.')[0]) + self.flavor = flavor.lower() self.packages = [ 'autoconf213', @@ -24,8 +25,11 @@ class FreeBSDBootstrapper(BaseBootstrapper): 'zip', ] + if self.flavor == 'dragonfly': + self.packages.append('unzip') + # gcc in base is too old - if self.version < 9: + if self.flavor == 'freebsd' and self.version < 9: self.packages.append('gcc') def pkg_install(self, *packages): From 2cc64dd3e81cab2a8c913d58af41cf980310f9c0 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Mon, 9 Jun 2014 22:17:01 +0200 Subject: [PATCH 31/52] Backing out 400d92d915f4 (bug 938186) for opt build oranges, r=me --- netwerk/cache2/CacheEntry.cpp | 47 ++----------------- netwerk/cache2/CacheEntry.h | 13 ++--- netwerk/cache2/nsICacheStorage.idl | 8 ---- .../test/unit/test_cache2-01f-basic-async.js | 28 ----------- .../test/unit/test_cache2-24-force-async.js | 42 ----------------- netwerk/test/unit/xpcshell.ini | 2 - 6 files changed, 9 insertions(+), 131 deletions(-) delete mode 100644 netwerk/test/unit/test_cache2-01f-basic-async.js delete mode 100644 netwerk/test/unit/test_cache2-24-force-async.js diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index 086f34bf5a5b..6af10d3a2e2f 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -76,7 +76,7 @@ CacheEntryHandle::~CacheEntryHandle() CacheEntry::Callback::Callback(CacheEntry* aEntry, nsICacheEntryOpenCallback *aCallback, - bool aReadOnly, bool aCheckOnAnyThread, bool aForceAsync) + bool aReadOnly, bool aCheckOnAnyThread) : mEntry(aEntry) , mCallback(aCallback) , mTargetThread(do_GetCurrentThread()) @@ -84,7 +84,6 @@ CacheEntry::Callback::Callback(CacheEntry* aEntry, , mCheckOnAnyThread(aCheckOnAnyThread) , mRecheckAfterWrite(false) , mNotWanted(false) -, mForceAsync(aForceAsync) { MOZ_COUNT_CTOR(CacheEntry::Callback); @@ -102,7 +101,6 @@ CacheEntry::Callback::Callback(CacheEntry::Callback const &aThat) , mCheckOnAnyThread(aThat.mCheckOnAnyThread) , mRecheckAfterWrite(aThat.mRecheckAfterWrite) , mNotWanted(aThat.mNotWanted) -, mForceAsync(aThat.mForceAsync) { MOZ_COUNT_CTOR(CacheEntry::Callback); @@ -133,19 +131,8 @@ void CacheEntry::Callback::ExchangeEntry(CacheEntry* aEntry) mEntry = aEntry; } -nsresult CacheEntry::Callback::OnCheckThread(bool *aOnCheckThread) +nsresult CacheEntry::Callback::OnCheckThread(bool *aOnCheckThread) const { - if (mForceAsync) { - // Drop the flag now. First time we must claim we are not on the proper thread - // what will simply force a post. But, the post does the check again and that - // time we must already tell the true we are on the proper thread otherwise we - // just loop indefinitely. Also, we need to post only once the first - // InvokeCallback for this callback. - mForceAsync = false; - *aOnCheckThread = false; - return NS_OK; - } - if (!mCheckOnAnyThread) { // Check we are on the target return mTargetThread->IsOnCurrentThread(aOnCheckThread); @@ -183,7 +170,6 @@ CacheEntry::CacheEntry(const nsACString& aStorageID, , mIsDoomed(false) , mSecurityInfoLoaded(false) , mPreventCallbacks(false) -, mDispatchingCallbacks(false) , mHasData(false) , mState(NOTLOADED) , mRegistration(NEVERREGISTERED) @@ -282,12 +268,11 @@ void CacheEntry::AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags bool truncate = aFlags & nsICacheStorage::OPEN_TRUNCATE; bool priority = aFlags & nsICacheStorage::OPEN_PRIORITY; bool multithread = aFlags & nsICacheStorage::CHECK_MULTITHREADED; - bool async = aFlags & nsICacheStorage::FORCE_ASYNC_CALLBACK; MOZ_ASSERT(!readonly || !truncate, "Bad flags combination"); MOZ_ASSERT(!(truncate && mState > LOADING), "Must not call truncate on already loaded entry"); - Callback callback(this, aCallback, readonly, multithread, async); + Callback callback(this, aCallback, readonly, multithread); mozilla::MutexAutoLock lock(mLock); @@ -524,14 +509,9 @@ void CacheEntry::RememberCallback(Callback & aCallback, bool aBypassIfBusy) mCallbacks.AppendElement(aCallback); } -void CacheEntry::InvokeDispatchedCallbacks() +void CacheEntry::InvokeCallbacksLock() { - LOG(("CacheEntry::InvokeDispatchedCallbacks [this=%p]", this)); - mozilla::MutexAutoLock lock(mLock); - - MOZ_ASSERT(mDispatchingCallbacks); - mDispatchingCallbacks = false; InvokeCallbacks(); } @@ -559,11 +539,6 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly) return false; } - if (mDispatchingCallbacks) { - LOG((" waiting for re-redispatch!")); - return false; - } - if (!mIsDoomed && (mState == WRITING || mState == REVALIDATING)) { LOG((" entry is being written/revalidated")); return false; @@ -581,17 +556,10 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly) if (NS_SUCCEEDED(rv) && !onCheckThread) { // Redispatch to the target thread nsRefPtr > event = - NS_NewRunnableMethod(this, &CacheEntry::InvokeDispatchedCallbacks); + NS_NewRunnableMethod(this, &CacheEntry::InvokeCallbacksLock); rv = mCallbacks[i].mTargetThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); if (NS_SUCCEEDED(rv)) { - // Setting this flag up prevents invocation of any callbacks until - // InvokeDispatchedCallbacks is fired on the target thread as a precaution - // of any unexpected call to InvokeCallbacks during climb back on the stack. - // E.g. GC could release a write handler that invokes callbacks immediately. - // Note: InvokeDispatchedCallbacks acquires the lock before checking/dropping - // this flag. - mDispatchingCallbacks = true; LOG((" re-dispatching to target thread")); return false; } @@ -621,11 +589,6 @@ bool CacheEntry::InvokeCallback(Callback & aCallback) mLock.AssertCurrentThreadOwns(); - if (mDispatchingCallbacks) { - LOG((" waiting for callbacks re-dispatch")); - return false; - } - // When this entry is doomed we want to notify the callback any time if (!mIsDoomed) { // When we are here, the entry must be loaded from disk diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h index a1fb32b18251..e4ec3d72dbf9 100644 --- a/netwerk/cache2/CacheEntry.h +++ b/netwerk/cache2/CacheEntry.h @@ -135,7 +135,7 @@ private: public: Callback(CacheEntry* aEntry, nsICacheEntryOpenCallback *aCallback, - bool aReadOnly, bool aCheckOnAnyThread, bool aForceAsync); + bool aReadOnly, bool aCheckOnAnyThread); Callback(Callback const &aThat); ~Callback(); @@ -153,9 +153,8 @@ private: bool mCheckOnAnyThread : 1; bool mRecheckAfterWrite : 1; bool mNotWanted : 1; - bool mForceAsync : 1; - nsresult OnCheckThread(bool *aOnCheckThread); + nsresult OnCheckThread(bool *aOnCheckThread) const; nsresult OnAvailThread(bool *aOnAvailThread) const; }; @@ -212,7 +211,7 @@ private: void OnLoaded(); void RememberCallback(Callback & aCallback, bool aBypassIfBusy); - void InvokeDispatchedCallbacks(); + void InvokeCallbacksLock(); void InvokeCallbacks(); bool InvokeCallbacks(bool aReadOnly); bool InvokeCallback(Callback & aCallback); @@ -278,12 +277,8 @@ private: // Whether security info has already been looked up in metadata. bool mSecurityInfoLoaded : 1; - // Prevents any callback invocation, used to not loop when we're recreating this entry. + // Prevents any callback invocation bool mPreventCallbacks : 1; - // Set at true between redispatch of callbacks from InvokeCallbacks and call of - // InvokeDispatchedCallbacks on the target thread. Prevents any callback invocation - // during that time. - bool mDispatchingCallbacks : 1; // true: after load and an existing file, or after output stream has been opened. // note - when opening an input stream, and this flag is false, output stream // is open along ; this makes input streams on new entries behave correctly diff --git a/netwerk/cache2/nsICacheStorage.idl b/netwerk/cache2/nsICacheStorage.idl index d465329d52c9..ca6f948b085a 100644 --- a/netwerk/cache2/nsICacheStorage.idl +++ b/netwerk/cache2/nsICacheStorage.idl @@ -50,13 +50,6 @@ interface nsICacheStorage : nsISupports */ const uint32_t CHECK_MULTITHREADED = 1 << 4; - /** - * Forces the callback to be invoked always only asynchronously regardless - * we have all the information to invoke it directly from inside asyncOpenURI - * method. - */ - const uint32_t FORCE_ASYNC_CALLBACK = 1 << 5; - /** * Asynchronously opens a cache entry for the specified URI. * Result is fetched asynchronously via the callback. @@ -76,7 +69,6 @@ interface nsICacheStorage : nsISupports * OPEN_BYPASS_IF_BUSY - backward compatibility only, LOAD_BYPASS_LOCAL_CACHE_IF_BUSY * CHECK_MULTITHREADED - onCacheEntryCheck may be called on any thread, consumer * implementation is thread-safe - * FORCE_ASYNC_CALLBACK - always call the callback asynchronously * @param aCallback * The consumer that receives the result. * IMPORTANT: The callback may be called sooner the method returns. diff --git a/netwerk/test/unit/test_cache2-01f-basic-async.js b/netwerk/test/unit/test_cache2-01f-basic-async.js deleted file mode 100644 index 5cda7b5b6501..000000000000 --- a/netwerk/test/unit/test_cache2-01f-basic-async.js +++ /dev/null @@ -1,28 +0,0 @@ -function run_test() -{ - do_get_profile(); - - // Open for write, write - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, - new OpenCallback(NEW, "a1m", "a1d", function(entry) { - // Open for read and check - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, - new OpenCallback(NORMAL, "a1m", "a1d", function(entry) { - // Open for rewrite (truncate), write different meta and data - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_TRUNCATE | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, - new OpenCallback(NEW, "a2m", "a2d", function(entry) { - // Open for read and check - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, - new OpenCallback(NORMAL, "a2m", "a2d", function(entry) { - finish_cache2_test(); - }) - ); - }) - ); - }) - ); - }) - ); - - do_test_pending(); -} diff --git a/netwerk/test/unit/test_cache2-24-force-async.js b/netwerk/test/unit/test_cache2-24-force-async.js deleted file mode 100644 index 5cd4f153aa0f..000000000000 --- a/netwerk/test/unit/test_cache2-24-force-async.js +++ /dev/null @@ -1,42 +0,0 @@ -function run_test() -{ - do_get_profile(); - - // Open for write, write, and wait for finishing it before notification to avoid concurrent write - // since we want to get as much as possible the scenario when an entry is left in the pool - // and a new consumer comes to open it later. - var outOfAsyncOpen0 = false; - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, - new OpenCallback(NEW|WAITFORWRITE, "a1m", "a1d", function(entry) { - do_check_true(outOfAsyncOpen0); - // Open for read, expect callback happen from inside asyncOpenURI - var outOfAsyncOpen1 = false; - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null, - function(entry) { - do_check_false(outOfAsyncOpen1); - var outOfAsyncOpen2 = false; - // Open for read, again should be sync - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null, - function(entry) { - do_check_false(outOfAsyncOpen2); - var outOfAsyncOpen3 = false; - // Open for read, expect callback happen from outside of asyncOpenURI - asyncOpenCacheEntry("http://a/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY | Ci.nsICacheStorage.FORCE_ASYNC_CALLBACK, null, - function(entry) { - do_check_true(outOfAsyncOpen3); - finish_cache2_test(); - } - ); - outOfAsyncOpen3 = true; - } - ); - outOfAsyncOpen2 = true; - } - ); - outOfAsyncOpen1 = true; - }) - ); - outOfAsyncOpen0 = true; - - do_test_pending(); -} diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index 9f50f94147bb..33e637bcf9e6 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -25,7 +25,6 @@ support-files = [test_cache2-01c-basic-hasmeta-only.js] [test_cache2-01d-basic-not-wanted.js] [test_cache2-01e-basic-bypass-if-busy.js] -[test_cache2-01f-basic-async.js] [test_cache2-02-open-non-existing.js] [test_cache2-03-oncacheentryavail-throws.js] [test_cache2-04-oncacheentryavail-throws2x.js] @@ -58,7 +57,6 @@ skip-if = os == "android" [test_cache2-21-anon-storage.js] [test_cache2-22-anon-visit.js] [test_cache2-23-read-over-chunk.js] -[test_cache2-24-force-async.js] [test_304_responses.js] # Bug 675039: test hangs on Android-armv6 skip-if = os == "android" From 572c9b9d33f0a16fc49d2c2d47aaf73dac72f0ff Mon Sep 17 00:00:00 2001 From: Harsh Pathak Date: Mon, 9 Jun 2014 10:58:00 -0400 Subject: [PATCH 32/52] Bug 997370 - Update comment in nsIX509Cert.idl to reflect certificate fingerprint instead of public key. r=cviecco --- security/manager/ssl/public/nsIX509Cert.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/manager/ssl/public/nsIX509Cert.idl b/security/manager/ssl/public/nsIX509Cert.idl index 649b72801772..6617d5aab66c 100644 --- a/security/manager/ssl/public/nsIX509Cert.idl +++ b/security/manager/ssl/public/nsIX509Cert.idl @@ -74,7 +74,7 @@ interface nsIX509Cert : nsISupports { readonly attribute AString sha256Fingerprint; /** - * The fingerprint of the certificate's public key, + * The fingerprint of the certificate's DER encoding, * calculated using the SHA1 algorithm. */ readonly attribute AString sha1Fingerprint; From 325312988d89dbe03e6b32ec658220130f879d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Thu, 5 Jun 2014 11:08:00 -0400 Subject: [PATCH 33/52] Bug 1020927 - Part 1: Update OTS to 06372729b075619ec94aa2e075afcabc894b6069 so that WOFF2 can be disabled at build time. This excludes the change of 9f5b6e2e6a5c0182e4c89233aff8a4f6414d55e0 that was causing a crash. r=jfkthame --- gfx/ots/README.mozilla | 9 +- gfx/ots/include/opentype-sanitiser.h | 4 +- gfx/ots/ots-woff2.patch | 134 ---- gfx/ots/src/moz.build | 3 + gfx/ots/src/ots.cc | 10 +- gfx/ots/src/woff2.cc | 1022 ++++++++++++++++++++++++++ gfx/ots/src/woff2.h | 20 + 7 files changed, 1055 insertions(+), 147 deletions(-) delete mode 100644 gfx/ots/ots-woff2.patch create mode 100644 gfx/ots/src/woff2.cc create mode 100644 gfx/ots/src/woff2.h diff --git a/gfx/ots/README.mozilla b/gfx/ots/README.mozilla index 0525bdcb6f21..22a7762d15c8 100644 --- a/gfx/ots/README.mozilla +++ b/gfx/ots/README.mozilla @@ -2,9 +2,10 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/. Our reference repository is https://github.com/khaledhosny/ots/. -Current revision: d7d831edd171054c7974f5e0dec2fc19bf869574 +Current revision: 06372729b075619ec94aa2e075afcabc894b6069 -Applied local patches: - ots-visibility.patch - make Process function externally visible for Windows DLL (bug 711079) +Upstream files included: LICENSE, src/, include/ - ots-woff2 - disable WOFF2 support (bug 941019) +Additional files: README.mozilla, src/moz.build + +Additional patch: ots-visibility.patch (bug 711079). diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h index 71747a32f321..0230bd087d82 100644 --- a/gfx/ots/include/opentype-sanitiser.h +++ b/gfx/ots/include/opentype-sanitiser.h @@ -231,6 +231,8 @@ enum TableAction { // Signature of the function to be provided by the client to decide what action // to do for a given table. +// tag: table tag as an integer in big-endian byte order, independent of platform endianness +// user_data: user defined data that are passed to SetTableActionCallback() typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data); // Set a callback function that will be called when OTS needs to decide what to @@ -241,10 +243,8 @@ void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data); // -DOTS_DEBUG. void DisableDebugOutput(); -#ifdef MOZ_OTS_WOFF2 // Enable WOFF2 support(experimental). void EnableWOFF2(); -#endif } // namespace ots diff --git a/gfx/ots/ots-woff2.patch b/gfx/ots/ots-woff2.patch deleted file mode 100644 index 688b913447da..000000000000 --- a/gfx/ots/ots-woff2.patch +++ /dev/null @@ -1,134 +0,0 @@ -diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h ---- a/gfx/ots/include/opentype-sanitiser.h -+++ b/gfx/ots/include/opentype-sanitiser.h -@@ -236,14 +236,16 @@ typedef TableAction (*TableActionFunc)(u - // Set a callback function that will be called when OTS needs to decide what to - // do for a font table. - void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data); - - // Force to disable debug output even when the library is compiled with - // -DOTS_DEBUG. - void DisableDebugOutput(); - -+#ifdef MOZ_OTS_WOFF2 - // Enable WOFF2 support(experimental). - void EnableWOFF2(); -+#endif - - } // namespace ots - - #endif // OPENTYPE_SANITISER_H_ -diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc ---- a/gfx/ots/src/ots.cc -+++ b/gfx/ots/src/ots.cc -@@ -9,25 +9,29 @@ - - #include - #include - #include - #include - #include - #include - -+#ifdef MOZ_OTS_WOFF2 - #include "woff2.h" -+#endif - - // The OpenType Font File - // http://www.microsoft.com/typography/otspec/cmap.htm - - namespace { - - bool g_debug_output = true; -+#ifdef MOZ_OTS_WOFF2 - bool g_enable_woff2 = false; -+#endif - - ots::MessageFunc g_message_func = NULL; - void *g_message_user_data = NULL; - - ots::TableActionFunc g_table_action_func = NULL; - void *g_table_action_user_data = NULL; - - // Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer -@@ -395,16 +399,17 @@ bool ProcessWOFF(ots::OpenTypeFile *head - } - if (block_end != ots::Round4(length)) { - return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)"); - } - - return ProcessGeneric(header, woff_tag, output, data, length, tables, file); - } - -+#ifdef MOZ_OTS_WOFF2 - bool ProcessWOFF2(ots::OpenTypeFile *header, - ots::OTSStream *output, const uint8_t *data, size_t length) { - size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length); - if (decompressed_size == 0) { - return OTS_FAILURE(); - } - // decompressed font must be <= 30MB - if (decompressed_size > 30 * 1024 * 1024) { -@@ -413,16 +418,17 @@ bool ProcessWOFF2(ots::OpenTypeFile *hea - - std::vector decompressed_buffer(decompressed_size); - if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size, - data, length)) { - return OTS_FAILURE(); - } - return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size); - } -+#endif - - ots::TableAction GetTableAction(uint32_t tag) { - ots::TableAction action = ots::TABLE_ACTION_DEFAULT; - - if (g_table_action_func != NULL) { - action = g_table_action_func(htonl(tag), g_table_action_user_data); - } - -@@ -795,19 +801,21 @@ bool IsValidVersionTag(uint32_t tag) { - tag == Tag("true") || - tag == Tag("typ1"); - } - - void DisableDebugOutput() { - g_debug_output = false; - } - -+#ifdef MOZ_OTS_WOFF2 - void EnableWOFF2() { - g_enable_woff2 = true; - } -+#endif - - void SetMessageCallback(MessageFunc func, void *user_data) { - g_message_func = func; - g_message_user_data = user_data; - } - - void SetTableActionCallback(TableActionFunc func, void *user_data) { - g_table_action_func = func; -@@ -822,20 +830,22 @@ bool Process(OTSStream *output, const ui - - if (length < 4) { - return OTS_FAILURE_MSG_(&header, "file less than 4 bytes"); - } - - bool result; - if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { - result = ProcessWOFF(&header, output, data, length); -+#ifdef MOZ_OTS_WOFF2 - } else if (g_enable_woff2 && - data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && - data[3] == '2') { - result = ProcessWOFF2(&header, output, data, length); -+#endif - } else { - result = ProcessTTF(&header, output, data, length); - } - - for (unsigned i = 0; ; ++i) { - if (table_parsers[i].parse == NULL) break; - table_parsers[i].free(&header); - } diff --git a/gfx/ots/src/moz.build b/gfx/ots/src/moz.build index 0b00a6559369..0fd0cb975f8a 100644 --- a/gfx/ots/src/moz.build +++ b/gfx/ots/src/moz.build @@ -60,3 +60,6 @@ DEFINES['NOMINMAX'] = True if CONFIG['OS_TARGET'] == 'WINNT': DEFINES['OTS_DLL'] = True DEFINES['OTS_DLL_EXPORTS'] = True + +# Disable WOFF2 support. +DEFINES['OTS_DISABLE_WOFF2'] = True; diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc index f9b78212d7dd..d260256d1d1a 100644 --- a/gfx/ots/src/ots.cc +++ b/gfx/ots/src/ots.cc @@ -14,7 +14,7 @@ #include #include -#ifdef MOZ_OTS_WOFF2 +#ifndef OTS_DISABLE_WOFF2 #include "woff2.h" #endif @@ -24,9 +24,7 @@ namespace { bool g_debug_output = true; -#ifdef MOZ_OTS_WOFF2 bool g_enable_woff2 = false; -#endif ots::MessageFunc g_message_func = NULL; void *g_message_user_data = NULL; @@ -404,7 +402,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header, return ProcessGeneric(header, woff_tag, output, data, length, tables, file); } -#ifdef MOZ_OTS_WOFF2 +#ifndef OTS_DISABLE_WOFF2 bool ProcessWOFF2(ots::OpenTypeFile *header, ots::OTSStream *output, const uint8_t *data, size_t length) { size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length); @@ -806,11 +804,9 @@ void DisableDebugOutput() { g_debug_output = false; } -#ifdef MOZ_OTS_WOFF2 void EnableWOFF2() { g_enable_woff2 = true; } -#endif void SetMessageCallback(MessageFunc func, void *user_data) { g_message_func = func; @@ -835,7 +831,7 @@ bool Process(OTSStream *output, const uint8_t *data, size_t length) { bool result; if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { result = ProcessWOFF(&header, output, data, length); -#ifdef MOZ_OTS_WOFF2 +#ifndef OTS_DISABLE_WOFF2 } else if (g_enable_woff2 && data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') { diff --git a/gfx/ots/src/woff2.cc b/gfx/ots/src/woff2.cc new file mode 100644 index 000000000000..6da97cb12c58 --- /dev/null +++ b/gfx/ots/src/woff2.cc @@ -0,0 +1,1022 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is the implementation of decompression of the proposed WOFF Ultra +// Condensed file format. + +#include +#include +#include + +#include + +#include "third_party/brotli/src/brotli/dec/decode.h" + +#include "opentype-sanitiser.h" +#include "ots-memory-stream.h" +#include "ots.h" +#include "woff2.h" + +namespace { + +// simple glyph flags +const int kGlyfOnCurve = 1 << 0; +const int kGlyfXShort = 1 << 1; +const int kGlyfYShort = 1 << 2; +const int kGlyfRepeat = 1 << 3; +const int kGlyfThisXIsSame = 1 << 4; +const int kGlyfThisYIsSame = 1 << 5; + +// composite glyph flags +const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; +const int FLAG_WE_HAVE_A_SCALE = 1 << 3; +const int FLAG_MORE_COMPONENTS = 1 << 5; +const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; +const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; +const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; + +const size_t kSfntHeaderSize = 12; +const size_t kSfntEntrySize = 16; +const size_t kCheckSumAdjustmentOffset = 8; + +const size_t kEndPtsOfContoursOffset = 10; +const size_t kCompositeGlyphBegin = 10; + +// Note that the byte order is big-endian, not the same as ots.cc +#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d) + +const unsigned int kWoff2FlagsContinueStream = 1 << 4; +const unsigned int kWoff2FlagsTransform = 1 << 5; + +// Compression type values common to both short and long formats +const uint32_t kCompressionTypeMask = 0xf; +const uint32_t kCompressionTypeNone = 0; +const uint32_t kCompressionTypeGzip = 1; +const uint32_t kCompressionTypeBrotli = 2; + +// This is a special value for the short format only, as described in +// "Design for compressed header format" in draft doc. +const uint32_t kShortFlagsContinue = 3; + +const uint32_t kKnownTags[] = { + TAG('c', 'm', 'a', 'p'), // 0 + TAG('h', 'e', 'a', 'd'), // 1 + TAG('h', 'h', 'e', 'a'), // 2 + TAG('h', 'm', 't', 'x'), // 3 + TAG('m', 'a', 'x', 'p'), // 4 + TAG('n', 'a', 'm', 'e'), // 5 + TAG('O', 'S', '/', '2'), // 6 + TAG('p', 'o', 's', 't'), // 7 + TAG('c', 'v', 't', ' '), // 8 + TAG('f', 'p', 'g', 'm'), // 9 + TAG('g', 'l', 'y', 'f'), // 10 + TAG('l', 'o', 'c', 'a'), // 11 + TAG('p', 'r', 'e', 'p'), // 12 + TAG('C', 'F', 'F', ' '), // 13 + TAG('V', 'O', 'R', 'G'), // 14 + TAG('E', 'B', 'D', 'T'), // 15 + TAG('E', 'B', 'L', 'C'), // 16 + TAG('g', 'a', 's', 'p'), // 17 + TAG('h', 'd', 'm', 'x'), // 18 + TAG('k', 'e', 'r', 'n'), // 19 + TAG('L', 'T', 'S', 'H'), // 20 + TAG('P', 'C', 'L', 'T'), // 21 + TAG('V', 'D', 'M', 'X'), // 22 + TAG('v', 'h', 'e', 'a'), // 23 + TAG('v', 'm', 't', 'x'), // 24 + TAG('B', 'A', 'S', 'E'), // 25 + TAG('G', 'D', 'E', 'F'), // 26 + TAG('G', 'P', 'O', 'S'), // 27 + TAG('G', 'S', 'U', 'B'), // 28 +}; + +struct Point { + int x; + int y; + bool on_curve; +}; + +struct Table { + uint32_t tag; + uint32_t flags; + uint32_t src_offset; + uint32_t src_length; + + uint32_t transform_length; + + uint32_t dst_offset; + uint32_t dst_length; + + Table() + : tag(0), + flags(0), + src_offset(0), + src_length(0), + transform_length(0), + dst_offset(0), + dst_length(0) {} +}; + +// Based on section 6.1.1 of MicroType Express draft spec +bool Read255UShort(ots::Buffer* buf, unsigned int* value) { + static const int kWordCode = 253; + static const int kOneMoreByteCode2 = 254; + static const int kOneMoreByteCode1 = 255; + static const int kLowestUCode = 253; + uint8_t code = 0; + if (!buf->ReadU8(&code)) { + return OTS_FAILURE(); + } + if (code == kWordCode) { + uint16_t result = 0; + if (!buf->ReadU16(&result)) { + return OTS_FAILURE(); + } + *value = result; + return true; + } else if (code == kOneMoreByteCode1) { + uint8_t result = 0; + if (!buf->ReadU8(&result)) { + return OTS_FAILURE(); + } + *value = result + kLowestUCode; + return true; + } else if (code == kOneMoreByteCode2) { + uint8_t result = 0; + if (!buf->ReadU8(&result)) { + return OTS_FAILURE(); + } + *value = result + kLowestUCode * 2; + return true; + } else { + *value = code; + return true; + } +} + +bool ReadBase128(ots::Buffer* buf, uint32_t* value) { + uint32_t result = 0; + for (size_t i = 0; i < 5; ++i) { + uint8_t code = 0; + if (!buf->ReadU8(&code)) { + return OTS_FAILURE(); + } + // If any of the top seven bits are set then we're about to overflow. + if (result & 0xe0000000U) { + return OTS_FAILURE(); + } + result = (result << 7) | (code & 0x7f); + if ((code & 0x80) == 0) { + *value = result; + return true; + } + } + // Make sure not to exceed the size bound + return OTS_FAILURE(); +} + +// Caller must ensure that buffer overrun won't happen. +// TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class +// and use it across the code. +size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) { + dst[offset] = x >> 24; + dst[offset + 1] = x >> 16; + dst[offset + 2] = x >> 8; + dst[offset + 3] = x; + return offset + 4; +} + +size_t Store16(uint8_t* dst, size_t offset, int x) { + dst[offset] = x >> 8; + dst[offset + 1] = x; + return offset + 2; +} + +int WithSign(int flag, int baseval) { + assert(0 <= baseval && baseval < 65536); + return (flag & 1) ? baseval : -baseval; +} + +bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size, + unsigned int n_points, std::vector* result, + size_t* in_bytes_consumed) { + int x = 0; + int y = 0; + + // Early return if |in| buffer is too small. Each point consumes 1-4 bytes. + if (n_points > in_size) { + return OTS_FAILURE(); + } + unsigned int triplet_index = 0; + + for (unsigned int i = 0; i < n_points; ++i) { + uint8_t flag = flags_in[i]; + bool on_curve = !(flag >> 7); + flag &= 0x7f; + unsigned int n_data_bytes; + if (flag < 84) { + n_data_bytes = 1; + } else if (flag < 120) { + n_data_bytes = 2; + } else if (flag < 124) { + n_data_bytes = 3; + } else { + n_data_bytes = 4; + } + if (triplet_index + n_data_bytes > in_size || + triplet_index + n_data_bytes < triplet_index) { + return OTS_FAILURE(); + } + int dx, dy; + if (flag < 10) { + dx = 0; + dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]); + } else if (flag < 20) { + dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]); + dy = 0; + } else if (flag < 84) { + int b0 = flag - 20; + int b1 = in[triplet_index]; + dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4)); + dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f)); + } else if (flag < 120) { + int b0 = flag - 84; + dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]); + dy = WithSign(flag >> 1, + 1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]); + } else if (flag < 124) { + int b2 = in[triplet_index + 1]; + dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4)); + dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]); + } else { + dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]); + dy = WithSign(flag >> 1, + (in[triplet_index + 2] << 8) + in[triplet_index + 3]); + } + triplet_index += n_data_bytes; + // Possible overflow but coordinate values are not security sensitive + x += dx; + y += dy; + result->push_back(Point()); + Point& back = result->back(); + back.x = x; + back.y = y; + back.on_curve = on_curve; + } + *in_bytes_consumed = triplet_index; + return true; +} + +// This function stores just the point data. On entry, dst points to the +// beginning of a simple glyph. Returns true on success. +bool StorePoints(const std::vector& points, + unsigned int n_contours, unsigned int instruction_length, + uint8_t* dst, size_t dst_size, size_t* glyph_size) { + // I believe that n_contours < 65536, in which case this is safe. However, a + // comment and/or an assert would be good. + unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 + + instruction_length; + int last_flag = -1; + int repeat_count = 0; + int last_x = 0; + int last_y = 0; + unsigned int x_bytes = 0; + unsigned int y_bytes = 0; + + for (size_t i = 0; i < points.size(); ++i) { + const Point& point = points.at(i); + int flag = point.on_curve ? kGlyfOnCurve : 0; + int dx = point.x - last_x; + int dy = point.y - last_y; + if (dx == 0) { + flag |= kGlyfThisXIsSame; + } else if (dx > -256 && dx < 256) { + flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0); + x_bytes += 1; + } else { + x_bytes += 2; + } + if (dy == 0) { + flag |= kGlyfThisYIsSame; + } else if (dy > -256 && dy < 256) { + flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0); + y_bytes += 1; + } else { + y_bytes += 2; + } + + if (flag == last_flag && repeat_count != 255) { + dst[flag_offset - 1] |= kGlyfRepeat; + repeat_count++; + } else { + if (repeat_count != 0) { + if (flag_offset >= dst_size) { + return OTS_FAILURE(); + } + dst[flag_offset++] = repeat_count; + } + if (flag_offset >= dst_size) { + return OTS_FAILURE(); + } + dst[flag_offset++] = flag; + repeat_count = 0; + } + last_x = point.x; + last_y = point.y; + last_flag = flag; + } + + if (repeat_count != 0) { + if (flag_offset >= dst_size) { + return OTS_FAILURE(); + } + dst[flag_offset++] = repeat_count; + } + unsigned int xy_bytes = x_bytes + y_bytes; + if (xy_bytes < x_bytes || + flag_offset + xy_bytes < flag_offset || + flag_offset + xy_bytes > dst_size) { + return OTS_FAILURE(); + } + + int x_offset = flag_offset; + int y_offset = flag_offset + x_bytes; + last_x = 0; + last_y = 0; + for (size_t i = 0; i < points.size(); ++i) { + int dx = points.at(i).x - last_x; + if (dx == 0) { + // pass + } else if (dx > -256 && dx < 256) { + dst[x_offset++] = std::abs(dx); + } else { + // will always fit for valid input, but overflow is harmless + x_offset = Store16(dst, x_offset, dx); + } + last_x += dx; + int dy = points.at(i).y - last_y; + if (dy == 0) { + // pass + } else if (dy > -256 && dy < 256) { + dst[y_offset++] = std::abs(dy); + } else { + y_offset = Store16(dst, y_offset, dy); + } + last_y += dy; + } + *glyph_size = y_offset; + return true; +} + +// Compute the bounding box of the coordinates, and store into a glyf buffer. +// A precondition is that there are at least 10 bytes available. +void ComputeBbox(const std::vector& points, uint8_t* dst) { + int x_min = 0; + int y_min = 0; + int x_max = 0; + int y_max = 0; + + for (size_t i = 0; i < points.size(); ++i) { + int x = points.at(i).x; + int y = points.at(i).y; + if (i == 0 || x < x_min) x_min = x; + if (i == 0 || x > x_max) x_max = x; + if (i == 0 || y < y_min) y_min = y; + if (i == 0 || y > y_max) y_max = y; + } + size_t offset = 2; + offset = Store16(dst, offset, x_min); + offset = Store16(dst, offset, y_min); + offset = Store16(dst, offset, x_max); + offset = Store16(dst, offset, y_max); +} + +// Process entire bbox stream. This is done as a separate pass to allow for +// composite bbox computations (an optional more aggressive transform). +bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs, + const std::vector& loca_values, uint8_t* glyf_buf, + size_t glyf_buf_length) { + const uint8_t* buf = bbox_stream->buffer(); + if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) { + return OTS_FAILURE(); + } + // Safe because n_glyphs is bounded + unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2; + if (!bbox_stream->Skip(bitmap_length)) { + return OTS_FAILURE(); + } + for (unsigned int i = 0; i < n_glyphs; ++i) { + if (buf[i >> 3] & (0x80 >> (i & 7))) { + uint32_t loca_offset = loca_values.at(i); + if (loca_values.at(i + 1) - loca_offset < kEndPtsOfContoursOffset) { + return OTS_FAILURE(); + } + if (glyf_buf_length < 2 + 10 || + loca_offset > glyf_buf_length - 2 - 10) { + return OTS_FAILURE(); + } + if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) { + return OTS_FAILURE(); + } + } + } + return true; +} + +bool ProcessComposite(ots::Buffer* composite_stream, uint8_t* dst, + size_t dst_size, size_t* glyph_size, bool* have_instructions) { + size_t start_offset = composite_stream->offset(); + bool we_have_instructions = false; + + uint16_t flags = FLAG_MORE_COMPONENTS; + while (flags & FLAG_MORE_COMPONENTS) { + if (!composite_stream->ReadU16(&flags)) { + return OTS_FAILURE(); + } + we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0; + size_t arg_size = 2; // glyph index + if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) { + arg_size += 4; + } else { + arg_size += 2; + } + if (flags & FLAG_WE_HAVE_A_SCALE) { + arg_size += 2; + } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) { + arg_size += 4; + } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) { + arg_size += 8; + } + if (!composite_stream->Skip(arg_size)) { + return OTS_FAILURE(); + } + } + size_t composite_glyph_size = composite_stream->offset() - start_offset; + if (composite_glyph_size + kCompositeGlyphBegin > dst_size) { + return OTS_FAILURE(); + } + Store16(dst, 0, 0xffff); // nContours = -1 for composite glyph + std::memcpy(dst + kCompositeGlyphBegin, + composite_stream->buffer() + start_offset, + composite_glyph_size); + *glyph_size = kCompositeGlyphBegin + composite_glyph_size; + *have_instructions = we_have_instructions; + return true; +} + +// Build TrueType loca table +bool StoreLoca(const std::vector& loca_values, int index_format, + uint8_t* dst, size_t dst_size) { + const uint64_t loca_size = loca_values.size(); + const uint64_t offset_size = index_format ? 4 : 2; + if ((loca_size << 2) >> 2 != loca_size) { + return OTS_FAILURE(); + } + // No integer overflow here (loca_size <= 2^16). + if (offset_size * loca_size > dst_size) { + return OTS_FAILURE(); + } + size_t offset = 0; + for (size_t i = 0; i < loca_values.size(); ++i) { + uint32_t value = loca_values.at(i); + if (index_format) { + offset = StoreU32(dst, offset, value); + } else { + offset = Store16(dst, offset, value >> 1); + } + } + return true; +} + +// Reconstruct entire glyf table based on transformed original +bool ReconstructGlyf(const uint8_t* data, size_t data_size, + uint8_t* dst, size_t dst_size, + uint8_t* loca_buf, size_t loca_size) { + static const int kNumSubStreams = 7; + ots::Buffer file(data, data_size); + uint32_t version; + std::vector > substreams(kNumSubStreams); + + if (!file.ReadU32(&version)) { + return OTS_FAILURE(); + } + uint16_t num_glyphs; + uint16_t index_format; + if (!file.ReadU16(&num_glyphs) || + !file.ReadU16(&index_format)) { + return OTS_FAILURE(); + } + unsigned int offset = (2 + kNumSubStreams) * 4; + if (offset > data_size) { + return OTS_FAILURE(); + } + // Invariant from here on: data_size >= offset + for (int i = 0; i < kNumSubStreams; ++i) { + uint32_t substream_size; + if (!file.ReadU32(&substream_size)) { + return OTS_FAILURE(); + } + if (substream_size > data_size - offset) { + return OTS_FAILURE(); + } + substreams.at(i) = std::make_pair(data + offset, substream_size); + offset += substream_size; + } + ots::Buffer n_contour_stream(substreams.at(0).first, substreams.at(0).second); + ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second); + ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second); + ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second); + ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); + ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); + ots::Buffer instruction_stream(substreams.at(6).first, + substreams.at(6).second); + + std::vector loca_values; + loca_values.reserve(num_glyphs + 1); + std::vector n_points_vec; + std::vector points; + uint32_t loca_offset = 0; + for (unsigned int i = 0; i < num_glyphs; ++i) { + size_t glyph_size = 0; + uint16_t n_contours = 0; + if (!n_contour_stream.ReadU16(&n_contours)) { + return OTS_FAILURE(); + } + uint8_t* glyf_dst = dst + loca_offset; + size_t glyf_dst_size = dst_size - loca_offset; + if (n_contours == 0xffff) { + // composite glyph + bool have_instructions = false; + unsigned int instruction_size = 0; + if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, + &glyph_size, &have_instructions)) { + return OTS_FAILURE(); + } + if (have_instructions) { + if (!Read255UShort(&glyph_stream, &instruction_size)) { + return OTS_FAILURE(); + } + // No integer overflow here (instruction_size < 2^16). + if (instruction_size + 2 > glyf_dst_size - glyph_size) { + return OTS_FAILURE(); + } + Store16(glyf_dst, glyph_size, instruction_size); + if (!instruction_stream.Read(glyf_dst + glyph_size + 2, + instruction_size)) { + return OTS_FAILURE(); + } + glyph_size += instruction_size + 2; + } + } else if (n_contours > 0) { + // simple glyph + n_points_vec.clear(); + points.clear(); + unsigned int total_n_points = 0; + unsigned int n_points_contour; + for (unsigned int j = 0; j < n_contours; ++j) { + if (!Read255UShort(&n_points_stream, &n_points_contour)) { + return OTS_FAILURE(); + } + n_points_vec.push_back(n_points_contour); + if (total_n_points + n_points_contour < total_n_points) { + return OTS_FAILURE(); + } + total_n_points += n_points_contour; + } + unsigned int flag_size = total_n_points; + if (flag_size > flag_stream.length() - flag_stream.offset()) { + return OTS_FAILURE(); + } + const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset(); + const uint8_t* triplet_buf = glyph_stream.buffer() + + glyph_stream.offset(); + size_t triplet_size = glyph_stream.length() - glyph_stream.offset(); + size_t triplet_bytes_consumed = 0; + if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points, + &points, &triplet_bytes_consumed)) { + return OTS_FAILURE(); + } + const uint32_t header_and_endpts_contours_size = + kEndPtsOfContoursOffset + 2 * n_contours; + if (glyf_dst_size < header_and_endpts_contours_size) { + return OTS_FAILURE(); + } + Store16(glyf_dst, 0, n_contours); + ComputeBbox(points, glyf_dst); + size_t endpts_offset = kEndPtsOfContoursOffset; + int end_point = -1; + for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) { + end_point += n_points_vec.at(contour_ix); + if (end_point >= 65536) { + return OTS_FAILURE(); + } + endpts_offset = Store16(glyf_dst, endpts_offset, end_point); + } + if (!flag_stream.Skip(flag_size)) { + return OTS_FAILURE(); + } + if (!glyph_stream.Skip(triplet_bytes_consumed)) { + return OTS_FAILURE(); + } + unsigned int instruction_size; + if (!Read255UShort(&glyph_stream, &instruction_size)) { + return OTS_FAILURE(); + } + // No integer overflow here (instruction_size < 2^16). + if (glyf_dst_size - header_and_endpts_contours_size < + instruction_size + 2) { + return OTS_FAILURE(); + } + uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; + Store16(instruction_dst, 0, instruction_size); + if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) { + return OTS_FAILURE(); + } + if (!StorePoints(points, n_contours, instruction_size, + glyf_dst, glyf_dst_size, &glyph_size)) { + return OTS_FAILURE(); + } + } else { + glyph_size = 0; + } + loca_values.push_back(loca_offset); + if (glyph_size + 3 < glyph_size) { + return OTS_FAILURE(); + } + glyph_size = ots::Round2(glyph_size); + if (glyph_size > dst_size - loca_offset) { + // This shouldn't happen, but this test defensively maintains the + // invariant that loca_offset <= dst_size. + return OTS_FAILURE(); + } + loca_offset += glyph_size; + } + loca_values.push_back(loca_offset); + assert(loca_values.size() == static_cast(num_glyphs + 1)); + if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values, + dst, dst_size)) { + return OTS_FAILURE(); + } + return StoreLoca(loca_values, index_format, loca_buf, loca_size); +} + +// This is linear search, but could be changed to binary because we +// do have a guarantee that the tables are sorted by tag. But the total +// cpu time is expected to be very small in any case. +const Table* FindTable(const std::vector& tables, uint32_t tag) { + size_t n_tables = tables.size(); + for (size_t i = 0; i < n_tables; ++i) { + if (tables.at(i).tag == tag) { + return &tables.at(i); + } + } + return NULL; +} + +bool ReconstructTransformed(const std::vector
& tables, uint32_t tag, + const uint8_t* transformed_buf, size_t transformed_size, + uint8_t* dst, size_t dst_length) { + if (tag == TAG('g', 'l', 'y', 'f')) { + const Table* glyf_table = FindTable(tables, tag); + const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a')); + if (glyf_table == NULL || loca_table == NULL) { + return OTS_FAILURE(); + } + if (static_cast(glyf_table->dst_offset) + glyf_table->dst_length > + dst_length) { + return OTS_FAILURE(); + } + if (static_cast(loca_table->dst_offset) + loca_table->dst_length > + dst_length) { + return OTS_FAILURE(); + } + return ReconstructGlyf(transformed_buf, transformed_size, + dst + glyf_table->dst_offset, glyf_table->dst_length, + dst + loca_table->dst_offset, loca_table->dst_length); + } else if (tag == TAG('l', 'o', 'c', 'a')) { + // processing was already done by glyf table, but validate + if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) { + return OTS_FAILURE(); + } + } else { + // transform for the tag is not known + return OTS_FAILURE(); + } + return true; +} + +uint32_t ComputeChecksum(const uint8_t* buf, size_t size) { + uint32_t checksum = 0; + for (size_t i = 0; i < size; i += 4) { + // We assume the addition is mod 2^32, which is valid because unsigned + checksum += (buf[i] << 24) | (buf[i + 1] << 16) | + (buf[i + 2] << 8) | buf[i + 3]; + } + return checksum; +} + +bool FixChecksums(const std::vector
& tables, uint8_t* dst) { + const Table* head_table = FindTable(tables, TAG('h', 'e', 'a', 'd')); + if (head_table == NULL || + head_table->dst_length < kCheckSumAdjustmentOffset + 4) { + return OTS_FAILURE(); + } + size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset; + if (adjustment_offset < head_table->dst_offset) { + return OTS_FAILURE(); + } + StoreU32(dst, adjustment_offset, 0); + size_t n_tables = tables.size(); + uint32_t file_checksum = 0; + for (size_t i = 0; i < n_tables; ++i) { + const Table* table = &tables.at(i); + size_t table_length = table->dst_length; + uint8_t* table_data = dst + table->dst_offset; + uint32_t checksum = ComputeChecksum(table_data, table_length); + StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum); + file_checksum += checksum; // The addition is mod 2^32 + } + file_checksum += ComputeChecksum(dst, + kSfntHeaderSize + kSfntEntrySize * n_tables); + uint32_t checksum_adjustment = 0xb1b0afba - file_checksum; + StoreU32(dst, adjustment_offset, checksum_adjustment); + return true; +} + +bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size, + const uint8_t* src_buf, size_t src_size, uint32_t compression_type) { + if (compression_type == kCompressionTypeGzip) { + uLongf uncompressed_length = dst_size; + int r = uncompress(reinterpret_cast(dst_buf), &uncompressed_length, + src_buf, src_size); + if (r != Z_OK || uncompressed_length != dst_size) { + return OTS_FAILURE(); + } + return true; + } else if (compression_type == kCompressionTypeBrotli) { + size_t uncompressed_size = dst_size; + int ok = BrotliDecompressBuffer(src_size, src_buf, + &uncompressed_size, dst_buf); + if (!ok || uncompressed_size != dst_size) { + return OTS_FAILURE(); + } + return true; + } + // Unknown compression type + return OTS_FAILURE(); +} + +bool ReadShortDirectory(ots::Buffer* file, std::vector
* tables, + size_t num_tables) { + uint32_t last_compression_type = 0; + for (size_t i = 0; i < num_tables; ++i) { + Table* table = &tables->at(i); + uint8_t flag_byte; + if (!file->ReadU8(&flag_byte)) { + return OTS_FAILURE(); + } + uint32_t tag; + if ((flag_byte & 0x1f) == 0x1f) { + if (!file->ReadU32(&tag)) { + return OTS_FAILURE(); + } + } else { + if ((flag_byte & 0x1f) >= arraysize(kKnownTags)) { + return OTS_FAILURE(); + } + tag = kKnownTags[flag_byte & 0x1f]; + } + uint32_t flags = flag_byte >> 6; + if (flags == kShortFlagsContinue) { + flags = last_compression_type | kWoff2FlagsContinueStream; + } else { + if (flags == kCompressionTypeNone || + flags == kCompressionTypeGzip || + flags == kCompressionTypeBrotli) { + last_compression_type = flags; + } else { + return OTS_FAILURE(); + } + } + if ((flag_byte & 0x20) != 0) { + flags |= kWoff2FlagsTransform; + } + uint32_t dst_length; + if (!ReadBase128(file, &dst_length)) { + return OTS_FAILURE(); + } + uint32_t transform_length = dst_length; + if ((flags & kWoff2FlagsTransform) != 0) { + if (!ReadBase128(file, &transform_length)) { + return OTS_FAILURE(); + } + } + uint32_t src_length = transform_length; + if ((flag_byte >> 6) == 1 || (flag_byte >> 6) == 2) { + if (!ReadBase128(file, &src_length)) { + return OTS_FAILURE(); + } + } else if (static_cast(flag_byte >> 6) == kShortFlagsContinue) { + // The compressed data for this table is in a previuos table, so we set + // the src_length to zero. + src_length = 0; + } + // Disallow huge numbers (> 1GB) for sanity. + if (src_length > 1024 * 1024 * 1024 || + transform_length > 1024 * 1024 * 1024 || + dst_length > 1024 * 1024 * 1024) { + return OTS_FAILURE(); + } + + table->tag = tag; + table->flags = flags; + table->src_length = src_length; + table->transform_length = transform_length; + table->dst_length = dst_length; + } + return true; +} + +} // namespace + +namespace ots { + +size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) { + ots::Buffer file(data, length); + uint32_t total_length; + + if (!file.Skip(16) || + !file.ReadU32(&total_length)) { + return 0; + } + return total_length; +} + +bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length, + const uint8_t* data, size_t length) { + static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2" + ots::Buffer file(data, length); + + uint32_t signature; + uint32_t flavor; + if (!file.ReadU32(&signature) || signature != kWoff2Signature || + !file.ReadU32(&flavor)) { + return OTS_FAILURE(); + } + + if (!IsValidVersionTag(ntohl(flavor))) { + return OTS_FAILURE(); + } + + uint32_t reported_length; + if (!file.ReadU32(&reported_length) || length != reported_length) { + return OTS_FAILURE(); + } + uint16_t num_tables; + if (!file.ReadU16(&num_tables) || !num_tables) { + return OTS_FAILURE(); + } + // We don't care about these fields of the header: + // uint16_t reserved + // uint32_t total_sfnt_size + // uint16_t major_version, minor_version + // uint32_t meta_offset, meta_length, meta_orig_length + // uint32_t priv_offset, priv_length + if (!file.Skip(30)) { + return OTS_FAILURE(); + } + std::vector
tables(num_tables); + if (!ReadShortDirectory(&file, &tables, num_tables)) { + return OTS_FAILURE(); + } + uint64_t src_offset = file.offset(); + uint64_t dst_offset = kSfntHeaderSize + + kSfntEntrySize * static_cast(num_tables); + uint64_t uncompressed_sum = 0; + for (uint16_t i = 0; i < num_tables; ++i) { + Table* table = &tables.at(i); + table->src_offset = src_offset; + src_offset += table->src_length; + if (src_offset > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + src_offset = ots::Round4(src_offset); + table->dst_offset = dst_offset; + dst_offset += table->dst_length; + if (dst_offset > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + dst_offset = ots::Round4(dst_offset); + if ((table->flags & kCompressionTypeMask) != kCompressionTypeNone) { + uncompressed_sum += table->src_length; + if (uncompressed_sum > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + } + } + // Enforce same 30M limit on uncompressed tables as OTS + if (uncompressed_sum > 30 * 1024 * 1024) { + return OTS_FAILURE(); + } + if (src_offset > length || dst_offset > result_length) { + return OTS_FAILURE(); + } + + const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables; + if (sfnt_header_and_table_directory_size > result_length) { + return OTS_FAILURE(); + } + + // Start building the font + size_t offset = 0; + offset = StoreU32(result, offset, flavor); + offset = Store16(result, offset, num_tables); + unsigned max_pow2 = 0; + while (1u << (max_pow2 + 1) <= num_tables) { + max_pow2++; + } + const uint16_t output_search_range = (1u << max_pow2) << 4; + offset = Store16(result, offset, output_search_range); + offset = Store16(result, offset, max_pow2); + offset = Store16(result, offset, (num_tables << 4) - output_search_range); + for (uint16_t i = 0; i < num_tables; ++i) { + const Table* table = &tables.at(i); + offset = StoreU32(result, offset, table->tag); + offset = StoreU32(result, offset, 0); // checksum, to fill in later + offset = StoreU32(result, offset, table->dst_offset); + offset = StoreU32(result, offset, table->dst_length); + } + std::vector uncompressed_buf; + bool continue_valid = false; + const uint8_t* transform_buf = NULL; + for (uint16_t i = 0; i < num_tables; ++i) { + const Table* table = &tables.at(i); + uint32_t flags = table->flags; + const uint8_t* src_buf = data + table->src_offset; + uint32_t compression_type = flags & kCompressionTypeMask; + size_t transform_length = table->transform_length; + if ((flags & kWoff2FlagsContinueStream) != 0) { + if (!continue_valid) { + return OTS_FAILURE(); + } + } else if (compression_type == kCompressionTypeNone) { + if (transform_length != table->src_length) { + return OTS_FAILURE(); + } + transform_buf = src_buf; + continue_valid = false; + } else if ((flags & kWoff2FlagsContinueStream) == 0) { + uint64_t total_size = transform_length; + for (uint16_t j = i + 1; j < num_tables; ++j) { + if ((tables.at(j).flags & kWoff2FlagsContinueStream) == 0) { + break; + } + total_size += tables.at(j).transform_length; + if (total_size > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + } + // Enforce same 30M limit on uncompressed tables as OTS + if (total_size > 30 * 1024 * 1024) { + return OTS_FAILURE(); + } + uncompressed_buf.resize(total_size); + if (!Woff2Uncompress(&uncompressed_buf[0], total_size, + src_buf, table->src_length, compression_type)) { + return OTS_FAILURE(); + } + transform_buf = &uncompressed_buf[0]; + continue_valid = true; + } else { + return OTS_FAILURE(); + } + + if ((flags & kWoff2FlagsTransform) == 0) { + if (transform_length != table->dst_length) { + return OTS_FAILURE(); + } + if (static_cast(table->dst_offset) + transform_length > + result_length) { + return OTS_FAILURE(); + } + std::memcpy(result + table->dst_offset, transform_buf, + transform_length); + } else { + if (!ReconstructTransformed(tables, table->tag, + transform_buf, transform_length, result, result_length)) { + return OTS_FAILURE(); + } + } + if (continue_valid) { + transform_buf += transform_length; + if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { + return OTS_FAILURE(); + } + } + } + + return FixChecksums(tables, result); +} + +} // namespace ots diff --git a/gfx/ots/src/woff2.h b/gfx/ots/src/woff2.h new file mode 100644 index 000000000000..f194e9548b87 --- /dev/null +++ b/gfx/ots/src/woff2.h @@ -0,0 +1,20 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef OTS_WOFF2_H_ +#define OTS_WOFF2_H_ + +namespace ots { + +// Compute the size of the final uncompressed font, or 0 on error. +size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length); + +// Decompresses the font into the target buffer. The result_length should +// be the same as determined by ComputeFinalSize(). Returns true on successful +// decompression. +bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length, + const uint8_t *data, size_t length); +} + +#endif // OTS_WOFF2_H_ From 111e726228bc07c7fbc05f14dc7ca2c065520e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Thu, 5 Jun 2014 11:09:00 -0400 Subject: [PATCH 34/52] Bug 1020927 - Part 2: Update OTS to bf4afceb8b441f3a219dd7cfea5613c18183836c so that we fix the compile warnings. r=jfkthame --- gfx/ots/README.mozilla | 2 +- gfx/ots/include/opentype-sanitiser.h | 55 ++++++++++++++++++++-------- gfx/ots/ots-visibility.patch | 54 ++++++--------------------- gfx/ots/src/cff.cc | 2 + gfx/ots/src/cmap.cc | 10 +++-- gfx/ots/src/cvt.cc | 2 + gfx/ots/src/fpgm.cc | 2 + gfx/ots/src/gasp.cc | 3 ++ gfx/ots/src/gdef.cc | 2 + gfx/ots/src/glyf.cc | 2 + gfx/ots/src/gpos.cc | 2 + gfx/ots/src/gsub.cc | 2 + gfx/ots/src/hdmx.cc | 3 ++ gfx/ots/src/head.cc | 2 + gfx/ots/src/hhea.cc | 2 + gfx/ots/src/hmtx.cc | 2 + gfx/ots/src/kern.cc | 3 ++ gfx/ots/src/layout.cc | 1 + gfx/ots/src/loca.cc | 2 + gfx/ots/src/ltsh.cc | 3 ++ gfx/ots/src/math.cc | 2 + gfx/ots/src/maxp.cc | 2 + gfx/ots/src/metrics.cc | 1 + gfx/ots/src/name.cc | 2 + gfx/ots/src/os2.cc | 2 + gfx/ots/src/ots.cc | 42 ++++++++------------- gfx/ots/src/ots.h | 11 ++++-- gfx/ots/src/post.cc | 2 + gfx/ots/src/prep.cc | 2 + gfx/ots/src/vdmx.cc | 3 ++ gfx/ots/src/vhea.cc | 1 + gfx/ots/src/vmtx.cc | 1 + gfx/ots/src/vorg.cc | 3 ++ gfx/thebes/gfxUserFontSet.cpp | 7 ++-- 34 files changed, 140 insertions(+), 97 deletions(-) diff --git a/gfx/ots/README.mozilla b/gfx/ots/README.mozilla index 22a7762d15c8..d316e41112e8 100644 --- a/gfx/ots/README.mozilla +++ b/gfx/ots/README.mozilla @@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/. Our reference repository is https://github.com/khaledhosny/ots/. -Current revision: 06372729b075619ec94aa2e075afcabc894b6069 +Current revision: bf4afceb8b441f3a219dd7cfea5613c18183836c Upstream files included: LICENSE, src/, include/ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h index 0230bd087d82..6657aca3c322 100644 --- a/gfx/ots/include/opentype-sanitiser.h +++ b/gfx/ots/include/opentype-sanitiser.h @@ -199,16 +199,6 @@ class OTSStream { unsigned chksum_buffer_offset_; }; -// ----------------------------------------------------------------------------- -// Process a given OpenType file and write out a sanitised version -// output: a pointer to an object implementing the OTSStream interface. The -// sanitisied output will be written to this. In the even of a failure, -// partial output may have been written. -// input: the OpenType file -// length: the size, in bytes, of |input| -// ----------------------------------------------------------------------------- -bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length); - // Signature of the function to be provided by the client in order to report errors. // The return type is a boolean so that it can be used within an expression, // but the actual value is ignored. (Suggested convention is to always return 'false'.) @@ -219,9 +209,6 @@ bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length); #endif typedef bool (*MessageFunc)(void *user_data, const char *format, ...) MSGFUNC_FMT_ATTR; -// Set a callback function that will be called when OTS is reporting an error. -void OTS_API SetMessageCallback(MessageFunc func, void *user_data); - enum TableAction { TABLE_ACTION_DEFAULT, // Use OTS's default action for that table TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it @@ -235,9 +222,45 @@ enum TableAction { // user_data: user defined data that are passed to SetTableActionCallback() typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data); -// Set a callback function that will be called when OTS needs to decide what to -// do for a font table. -void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data); +class OTS_API OTSContext { + public: + OTSContext() + : message_func(0), + message_user_data(0), + table_action_func(0), + table_action_user_data(0) + {} + + ~OTSContext() {} + + // Process a given OpenType file and write out a sanitised version + // output: a pointer to an object implementing the OTSStream interface. The + // sanitisied output will be written to this. In the even of a failure, + // partial output may have been written. + // input: the OpenType file + // length: the size, in bytes, of |input| + // context: optional context that holds various OTS settings like user callbacks + bool Process(OTSStream *output, const uint8_t *input, size_t length); + + // Set a callback function that will be called when OTS is reporting an error. + void SetMessageCallback(MessageFunc func, void *user_data) { + message_func = func; + message_user_data = user_data; + } + + // Set a callback function that will be called when OTS needs to decide what to + // do for a font table. + void SetTableActionCallback(TableActionFunc func, void *user_data) { + table_action_func = func; + table_action_user_data = user_data; + } + + private: + MessageFunc message_func; + void *message_user_data; + TableActionFunc table_action_func; + void *table_action_user_data; +}; // Force to disable debug output even when the library is compiled with // -DOTS_DEBUG. diff --git a/gfx/ots/ots-visibility.patch b/gfx/ots/ots-visibility.patch index ccec794160e3..fed3ea1f0b1c 100644 --- a/gfx/ots/ots-visibility.patch +++ b/gfx/ots/ots-visibility.patch @@ -37,52 +37,22 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san typedef unsigned short uint16_t; typedef int int32_t; typedef unsigned int uint32_t; -@@ -182,45 +202,45 @@ class OTSStream { - // ----------------------------------------------------------------------------- - // Process a given OpenType file and write out a sanitised version - // output: a pointer to an object implementing the OTSStream interface. The - // sanitisied output will be written to this. In the even of a failure, - // partial output may have been written. - // input: the OpenType file - // length: the size, in bytes, of |input| - // ----------------------------------------------------------------------------- --bool Process(OTSStream *output, const uint8_t *input, size_t length); -+bool OTS_API Process(OTSStream *output, const uint8_t *input, size_t length); - - // Signature of the function to be provided by the client in order to report errors. - // The return type is a boolean so that it can be used within an expression, - // but the actual value is ignored. (Suggested convention is to always return 'false'.) - #ifdef __GCC__ - #define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3))) - #else - #define MSGFUNC_FMT_ATTR - #endif - typedef bool (*MessageFunc)(void *user_data, const char *format, ...) MSGFUNC_FMT_ATTR; - - // Set a callback function that will be called when OTS is reporting an error. --void SetMessageCallback(MessageFunc func, void *user_data); -+void OTS_API SetMessageCallback(MessageFunc func, void *user_data); - - enum TableAction { - TABLE_ACTION_DEFAULT, // Use OTS's default action for that table - TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it - TABLE_ACTION_PASSTHRU, // Serialize the table unchanged - TABLE_ACTION_DROP // Drop the table +@@ -197,17 +217,17 @@ enum TableAction { }; // Signature of the function to be provided by the client to decide what action // to do for a given table. + // tag: table tag as an integer in big-endian byte order, independent of platform endianness + // user_data: user defined data that are passed to SetTableActionCallback() typedef TableAction (*TableActionFunc)(uint32_t tag, void *user_data); - // Set a callback function that will be called when OTS needs to decide what to - // do for a font table. --void SetTableActionCallback(TableActionFunc func, void *user_data); -+void OTS_API SetTableActionCallback(TableActionFunc func, void *user_data); - - // Force to disable debug output even when the library is compiled with - // -DOTS_DEBUG. - void DisableDebugOutput(); - - // Enable WOFF2 support(experimental). - void EnableWOFF2(); +-class OTSContext { ++class OTS_API OTSContext { + public: + OTSContext() + : message_func(0), + message_user_data(0), + table_action_func(0), + table_action_user_data(0) + {} diff --git a/gfx/ots/src/cff.cc b/gfx/ots/src/cff.cc index 63d6b56f9f95..2ed1e9fe8598 100644 --- a/gfx/ots/src/cff.cc +++ b/gfx/ots/src/cff.cc @@ -1028,3 +1028,5 @@ void ots_cff_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/cmap.cc b/gfx/ots/src/cmap.cc index 0a2dc6e1036a..1fa383c1fbda 100644 --- a/gfx/ots/src/cmap.cc +++ b/gfx/ots/src/cmap.cc @@ -360,8 +360,8 @@ bool Parse31013(ots::OpenTypeFile *file, if (!subtable.Skip(8)) { return OTS_FAILURE_MSG("Bad cmap subtable length"); } - uint16_t language = 0; - if (!subtable.ReadU16(&language)) { + uint32_t language = 0; + if (!subtable.ReadU32(&language)) { return OTS_FAILURE_MSG("Can't read cmap subtable language"); } if (language) { @@ -876,7 +876,7 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) { // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables // (e.g., old fonts for Mac). We don't support them. - if (!have_304 && !have_314 && !have_034) { + if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) { return OTS_FAILURE(); } @@ -1005,7 +1005,7 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) { = file->cmap->subtable_3_10_13; const unsigned num_groups = groups.size(); if (!out->WriteU16(13) || - !out->WriteU16(0) || + !out->WriteU32(0) || !out->WriteU32(num_groups * 12 + 14) || !out->WriteU32(0) || !out->WriteU32(num_groups)) { @@ -1101,3 +1101,5 @@ void ots_cmap_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/cvt.cc b/gfx/ots/src/cvt.cc index a6ab95de5a43..5f8830853d7c 100644 --- a/gfx/ots/src/cvt.cc +++ b/gfx/ots/src/cvt.cc @@ -56,3 +56,5 @@ void ots_cvt_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/fpgm.cc b/gfx/ots/src/fpgm.cc index 361d9e27fa28..ffc9b79f970a 100644 --- a/gfx/ots/src/fpgm.cc +++ b/gfx/ots/src/fpgm.cc @@ -50,3 +50,5 @@ void ots_fpgm_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/gasp.cc b/gfx/ots/src/gasp.cc index 4f91cf556578..8027fcb45599 100644 --- a/gfx/ots/src/gasp.cc +++ b/gfx/ots/src/gasp.cc @@ -110,3 +110,6 @@ void ots_gasp_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/gdef.cc b/gfx/ots/src/gdef.cc index 224e61075344..523d3848e4d1 100644 --- a/gfx/ots/src/gdef.cc +++ b/gfx/ots/src/gdef.cc @@ -384,3 +384,5 @@ void ots_gdef_free(OpenTypeFile *file) { } // namespace ots +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/glyf.cc b/gfx/ots/src/glyf.cc index a416208fe16b..a114a94f60b1 100644 --- a/gfx/ots/src/glyf.cc +++ b/gfx/ots/src/glyf.cc @@ -307,3 +307,5 @@ void ots_glyf_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/gpos.cc b/gfx/ots/src/gpos.cc index eeaf33afae8f..5cb3e5691adc 100644 --- a/gfx/ots/src/gpos.cc +++ b/gfx/ots/src/gpos.cc @@ -812,3 +812,5 @@ void ots_gpos_free(OpenTypeFile *file) { } // namespace ots +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/gsub.cc b/gfx/ots/src/gsub.cc index a278650ca582..9d7d75e73829 100644 --- a/gfx/ots/src/gsub.cc +++ b/gfx/ots/src/gsub.cc @@ -669,3 +669,5 @@ void ots_gsub_free(OpenTypeFile *file) { } // namespace ots +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/hdmx.cc b/gfx/ots/src/hdmx.cc index 4a6cf89ae507..bcf544eaf566 100644 --- a/gfx/ots/src/hdmx.cc +++ b/gfx/ots/src/hdmx.cc @@ -138,3 +138,6 @@ void ots_hdmx_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/head.cc b/gfx/ots/src/head.cc index d2a0a4f6662b..dcd234d24c00 100644 --- a/gfx/ots/src/head.cc +++ b/gfx/ots/src/head.cc @@ -149,3 +149,5 @@ void ots_head_free(OpenTypeFile *file) { } } // namespace + +#undef TABLE_NAME diff --git a/gfx/ots/src/hhea.cc b/gfx/ots/src/hhea.cc index e4ac9dca70bb..8430442d8ef6 100644 --- a/gfx/ots/src/hhea.cc +++ b/gfx/ots/src/hhea.cc @@ -49,3 +49,5 @@ void ots_hhea_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/hmtx.cc b/gfx/ots/src/hmtx.cc index dd26eec94d24..ae86513196a8 100644 --- a/gfx/ots/src/hmtx.cc +++ b/gfx/ots/src/hmtx.cc @@ -47,3 +47,5 @@ void ots_hmtx_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/kern.cc b/gfx/ots/src/kern.cc index fa071ab9c719..b1bfb50d28e4 100644 --- a/gfx/ots/src/kern.cc +++ b/gfx/ots/src/kern.cc @@ -200,3 +200,6 @@ void ots_kern_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/layout.cc b/gfx/ots/src/layout.cc index 6513d0775265..139a9d995893 100644 --- a/gfx/ots/src/layout.cc +++ b/gfx/ots/src/layout.cc @@ -1510,3 +1510,4 @@ bool ParseExtensionSubtable(const OpenTypeFile *file, } // namespace ots +#undef TABLE_NAME diff --git a/gfx/ots/src/loca.cc b/gfx/ots/src/loca.cc index 7d0a52d8aba0..fad088093a90 100644 --- a/gfx/ots/src/loca.cc +++ b/gfx/ots/src/loca.cc @@ -98,3 +98,5 @@ void ots_loca_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/ltsh.cc b/gfx/ots/src/ltsh.cc index 23cf7a26a2a7..a85b5250493b 100644 --- a/gfx/ots/src/ltsh.cc +++ b/gfx/ots/src/ltsh.cc @@ -86,3 +86,6 @@ void ots_ltsh_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/math.cc b/gfx/ots/src/math.cc index dd392faef337..e7f1607828f1 100644 --- a/gfx/ots/src/math.cc +++ b/gfx/ots/src/math.cc @@ -606,3 +606,5 @@ void ots_math_free(OpenTypeFile *file) { } // namespace ots +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/maxp.cc b/gfx/ots/src/maxp.cc index 911c7351b310..de514593134d 100644 --- a/gfx/ots/src/maxp.cc +++ b/gfx/ots/src/maxp.cc @@ -128,3 +128,5 @@ void ots_maxp_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/metrics.cc b/gfx/ots/src/metrics.cc index 0f6134a381ad..7a60d0cc5bd3 100644 --- a/gfx/ots/src/metrics.cc +++ b/gfx/ots/src/metrics.cc @@ -184,3 +184,4 @@ bool SerialiseMetricsTable(const ots::OpenTypeFile *file, } // namespace ots +#undef TABLE_NAME diff --git a/gfx/ots/src/name.cc b/gfx/ots/src/name.cc index fb73b3befa70..3b928219e527 100644 --- a/gfx/ots/src/name.cc +++ b/gfx/ots/src/name.cc @@ -332,3 +332,5 @@ void ots_name_free(OpenTypeFile* file) { } } // namespace + +#undef TABLE_NAME diff --git a/gfx/ots/src/os2.cc b/gfx/ots/src/os2.cc index c21bedaf0da6..915877e3b001 100644 --- a/gfx/ots/src/os2.cc +++ b/gfx/ots/src/os2.cc @@ -290,3 +290,5 @@ void ots_os2_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc index d260256d1d1a..1e4ed4b58641 100644 --- a/gfx/ots/src/ots.cc +++ b/gfx/ots/src/ots.cc @@ -26,12 +26,6 @@ namespace { bool g_debug_output = true; bool g_enable_woff2 = false; -ots::MessageFunc g_message_func = NULL; -void *g_message_user_data = NULL; - -ots::TableActionFunc g_table_action_func = NULL; -void *g_table_action_user_data = NULL; - // Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer #define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_) #define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE_MSG_(header, msg_) @@ -423,11 +417,11 @@ bool ProcessWOFF2(ots::OpenTypeFile *header, } #endif -ots::TableAction GetTableAction(uint32_t tag) { +ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) { ots::TableAction action = ots::TABLE_ACTION_DEFAULT; - if (g_table_action_func != NULL) { - action = g_table_action_func(htonl(tag), g_table_action_user_data); + if (header->table_action_func != NULL) { + action = header->table_action_func(htonl(tag), header->table_action_user_data); } if (action == ots::TABLE_ACTION_DEFAULT) { @@ -576,10 +570,10 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, for (unsigned i = 0; ; ++i) { if (table_parsers[i].parse == NULL) break; - const std::map::const_iterator it - = table_map.find(Tag(table_parsers[i].tag)); + uint32_t tag = Tag(table_parsers[i].tag); + const std::map::const_iterator it = table_map.find(tag); - ots::TableAction action = GetTableAction(Tag(table_parsers[i].tag)); + ots::TableAction action = GetTableAction(header, tag); if (it == table_map.end()) { if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) { return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag); @@ -632,7 +626,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, for (std::map::const_iterator it = table_map.begin(); it != table_map.end(); ++it) { - ots::TableAction action = GetTableAction(it->first); + ots::TableAction action = GetTableAction(header, it->first); if (action == ots::TABLE_ACTION_PASSTHRU) { num_output_tables++; } @@ -704,7 +698,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, for (std::map::const_iterator it = table_map.begin(); it != table_map.end(); ++it) { - ots::TableAction action = GetTableAction(it->first); + ots::TableAction action = GetTableAction(header, it->first); if (action == ots::TABLE_ACTION_PASSTHRU) { OutputTable out; out.tag = it->second.tag; @@ -808,21 +802,15 @@ void EnableWOFF2() { g_enable_woff2 = true; } -void SetMessageCallback(MessageFunc func, void *user_data) { - g_message_func = func; - g_message_user_data = user_data; -} - -void SetTableActionCallback(TableActionFunc func, void *user_data) { - g_table_action_func = func; - g_table_action_user_data = user_data; -} - -bool Process(OTSStream *output, const uint8_t *data, size_t length) { +bool OTSContext::Process(OTSStream *output, + const uint8_t *data, + size_t length) { OpenTypeFile header; - header.message_func = g_message_func; - header.user_data = g_message_user_data; + header.message_func = message_func; + header.message_user_data = message_user_data; + header.table_action_func = table_action_func; + header.table_action_user_data = table_action_user_data; if (length < 4) { return OTS_FAILURE_MSG_(&header, "file less than 4 bytes"); diff --git a/gfx/ots/src/ots.h b/gfx/ots/src/ots.h index 87cb310b8398..9c7b50f871ee 100644 --- a/gfx/ots/src/ots.h +++ b/gfx/ots/src/ots.h @@ -53,13 +53,13 @@ void Warning(const char *f, int l, const char *format, ...) // Generate a simple message #define OTS_FAILURE_MSG_(otf_,...) \ ((otf_)->message_func && \ - (*(otf_)->message_func)((otf_)->user_data, __VA_ARGS__) && \ + (*(otf_)->message_func)((otf_)->message_user_data, __VA_ARGS__) && \ false) // Generate a message with an associated table tag #define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \ ((otf_)->message_func && \ - (*(otf_)->message_func)((otf_)->user_data, "%4.4s: %s", tag_, msg_) && \ + (*(otf_)->message_func)((otf_)->message_user_data, "%4.4s: %s", tag_, msg_) && \ false) // Convenience macro for use in files that only handle a single table tag, @@ -250,8 +250,11 @@ struct OpenTypeFile { uint16_t entry_selector; uint16_t range_shift; - MessageFunc message_func; - void *user_data; + MessageFunc message_func; + void *message_user_data; + + TableActionFunc table_action_func; + void *table_action_user_data; #define F(name, capname) OpenType##capname *name; FOR_EACH_TABLE_TYPE diff --git a/gfx/ots/src/post.cc b/gfx/ots/src/post.cc index 6a5b897f419d..a887d9822fa3 100644 --- a/gfx/ots/src/post.cc +++ b/gfx/ots/src/post.cc @@ -180,3 +180,5 @@ void ots_post_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/prep.cc b/gfx/ots/src/prep.cc index 9a972c78eac2..f917f3b6825b 100644 --- a/gfx/ots/src/prep.cc +++ b/gfx/ots/src/prep.cc @@ -50,3 +50,5 @@ void ots_prep_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME diff --git a/gfx/ots/src/vdmx.cc b/gfx/ots/src/vdmx.cc index b65467fa8ab2..c6525ede22aa 100644 --- a/gfx/ots/src/vdmx.cc +++ b/gfx/ots/src/vdmx.cc @@ -181,3 +181,6 @@ void ots_vdmx_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/ots/src/vhea.cc b/gfx/ots/src/vhea.cc index 49ba92105e77..c689a834f0c1 100644 --- a/gfx/ots/src/vhea.cc +++ b/gfx/ots/src/vhea.cc @@ -56,3 +56,4 @@ void ots_vhea_free(OpenTypeFile *file) { } // namespace ots +#undef TABLE_NAME diff --git a/gfx/ots/src/vmtx.cc b/gfx/ots/src/vmtx.cc index f2481374efcb..e29d32b29f9b 100644 --- a/gfx/ots/src/vmtx.cc +++ b/gfx/ots/src/vmtx.cc @@ -52,3 +52,4 @@ void ots_vmtx_free(OpenTypeFile *file) { } // namespace ots +#undef TABLE_NAME diff --git a/gfx/ots/src/vorg.cc b/gfx/ots/src/vorg.cc index 3938f7cc0300..5e684a32d244 100644 --- a/gfx/ots/src/vorg.cc +++ b/gfx/ots/src/vorg.cc @@ -101,3 +101,6 @@ void ots_vorg_free(OpenTypeFile *file) { } } // namespace ots + +#undef TABLE_NAME +#undef DROP_THIS_TABLE diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index f5afac6d0ab0..8fbc908b7c52 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -388,10 +388,11 @@ gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily, userData.mFamily = aFamily; userData.mProxy = aProxy; - ots::SetTableActionCallback(&OTSTableAction, nullptr); - ots::SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData); + ots::OTSContext otsContext; + otsContext.SetTableActionCallback(&OTSTableAction, nullptr); + otsContext.SetMessageCallback(&gfxUserFontSet::OTSMessage, &userData); - if (ots::Process(&output, aData, aLength)) { + if (otsContext.Process(&output, aData, aLength)) { aSaneLength = output.Tell(); return static_cast(output.forget()); } else { From b7379c962bfa06a214a804886bba407a35b9b95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Thu, 5 Jun 2014 11:09:00 -0400 Subject: [PATCH 35/52] Bug 1020927 - Update OTS to d6018b62bf41f6b419aeae6d2795725a55715481 to accept 0 lookup for lookup, feature or script offset. r=jfkthame --- gfx/ots/README.mozilla | 2 +- gfx/ots/src/gpos.cc | 60 +++++++++++++++++++++++++----------------- gfx/ots/src/gsub.cc | 60 +++++++++++++++++++++++++----------------- 3 files changed, 73 insertions(+), 49 deletions(-) diff --git a/gfx/ots/README.mozilla b/gfx/ots/README.mozilla index d316e41112e8..d63fe0d45f73 100644 --- a/gfx/ots/README.mozilla +++ b/gfx/ots/README.mozilla @@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/. Our reference repository is https://github.com/khaledhosny/ots/. -Current revision: bf4afceb8b441f3a219dd7cfea5613c18183836c +Current revision: d6018b62bf41f6b419aeae6d2795725a55715481 Upstream files included: LICENSE, src/, include/ diff --git a/gfx/ots/src/gpos.cc b/gfx/ots/src/gpos.cc index 5cb3e5691adc..314cf2923e22 100644 --- a/gfx/ots/src/gpos.cc +++ b/gfx/ots/src/gpos.cc @@ -757,36 +757,48 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { DROP_THIS_TABLE("Bad version"); return true; } - if ((offset_script_list < kGposHeaderSize || - offset_script_list >= length) || - (offset_feature_list < kGposHeaderSize || - offset_feature_list >= length) || - (offset_lookup_list < kGposHeaderSize || - offset_lookup_list >= length)) { - DROP_THIS_TABLE("Bad offset in table header"); - return true; - } - if (!ParseLookupListTable(file, data + offset_lookup_list, - length - offset_lookup_list, - &kGposLookupSubtableParser, - &gpos->num_lookups)) { - DROP_THIS_TABLE("Failed to parse lookup list table"); - return true; + if (offset_lookup_list) { + if (offset_lookup_list < kGposHeaderSize || offset_lookup_list >= length) { + DROP_THIS_TABLE("Bad lookup list offset in table header"); + return true; + } + + if (!ParseLookupListTable(file, data + offset_lookup_list, + length - offset_lookup_list, + &kGposLookupSubtableParser, + &gpos->num_lookups)) { + DROP_THIS_TABLE("Failed to parse lookup list table"); + return true; + } } uint16_t num_features = 0; - if (!ParseFeatureListTable(file, data + offset_feature_list, - length - offset_feature_list, gpos->num_lookups, - &num_features)) { - DROP_THIS_TABLE("Failed to parse feature list table"); - return true; + if (offset_feature_list) { + if (offset_feature_list < kGposHeaderSize || offset_feature_list >= length) { + DROP_THIS_TABLE("Bad feature list offset in table header"); + return true; + } + + if (!ParseFeatureListTable(file, data + offset_feature_list, + length - offset_feature_list, gpos->num_lookups, + &num_features)) { + DROP_THIS_TABLE("Failed to parse feature list table"); + return true; + } } - if (!ParseScriptListTable(file, data + offset_script_list, - length - offset_script_list, num_features)) { - DROP_THIS_TABLE("Failed to parse script list table"); - return true; + if (offset_script_list) { + if (offset_script_list < kGposHeaderSize || offset_script_list >= length) { + DROP_THIS_TABLE("Bad script list offset in table header"); + return true; + } + + if (!ParseScriptListTable(file, data + offset_script_list, + length - offset_script_list, num_features)) { + DROP_THIS_TABLE("Failed to parse script list table"); + return true; + } } gpos->data = data; diff --git a/gfx/ots/src/gsub.cc b/gfx/ots/src/gsub.cc index 9d7d75e73829..4ff4214e343b 100644 --- a/gfx/ots/src/gsub.cc +++ b/gfx/ots/src/gsub.cc @@ -614,36 +614,48 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { DROP_THIS_TABLE("Bad version"); return true; } - if ((offset_script_list < kGsubHeaderSize || - offset_script_list >= length) || - (offset_feature_list < kGsubHeaderSize || - offset_feature_list >= length) || - (offset_lookup_list < kGsubHeaderSize || - offset_lookup_list >= length)) { - DROP_THIS_TABLE("Bad offset in table header"); - return true; - } - if (!ParseLookupListTable(file, data + offset_lookup_list, - length - offset_lookup_list, - &kGsubLookupSubtableParser, - &gsub->num_lookups)) { - DROP_THIS_TABLE("Failed to parse lookup list table"); - return true; + if (offset_lookup_list) { + if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) { + DROP_THIS_TABLE("Bad lookup list offset in table header"); + return true; + } + + if (!ParseLookupListTable(file, data + offset_lookup_list, + length - offset_lookup_list, + &kGsubLookupSubtableParser, + &gsub->num_lookups)) { + DROP_THIS_TABLE("Failed to parse lookup list table"); + return true; + } } uint16_t num_features = 0; - if (!ParseFeatureListTable(file, data + offset_feature_list, - length - offset_feature_list, gsub->num_lookups, - &num_features)) { - DROP_THIS_TABLE("Failed to parse feature list table"); - return true; + if (offset_feature_list) { + if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) { + DROP_THIS_TABLE("Bad feature list offset in table header"); + return true; + } + + if (!ParseFeatureListTable(file, data + offset_feature_list, + length - offset_feature_list, gsub->num_lookups, + &num_features)) { + DROP_THIS_TABLE("Failed to parse feature list table"); + return true; + } } - if (!ParseScriptListTable(file, data + offset_script_list, - length - offset_script_list, num_features)) { - DROP_THIS_TABLE("Failed to parse script list table"); - return true; + if (offset_script_list) { + if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) { + DROP_THIS_TABLE("Bad script list offset in table header"); + return true; + } + + if (!ParseScriptListTable(file, data + offset_script_list, + length - offset_script_list, num_features)) { + DROP_THIS_TABLE("Failed to parse script list table"); + return true; + } } gsub->data = data; From 6511b8c4c782ecb9bfb02e11db701c543e46900d Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Mon, 9 Jun 2014 10:40:00 -0400 Subject: [PATCH 36/52] Bug 1016578 - Enhancement: Easily inject jQuery, underscore, or other useful libraries into pages from devtools. r=jwalker --- browser/app/profile/firefox.js | 5 + .../devtools/commandline/commands-index.js | 1 + browser/devtools/commandline/test/browser.ini | 3 + .../commandline/test/browser_cmd_inject.html | 8 ++ .../commandline/test/browser_cmd_inject.js | 98 +++++++++++++++++++ .../commandline/test/browser_gcli_types.js | 4 + .../chrome/browser/devtools/gcli.properties | 4 + .../browser/devtools/gclicommands.properties | 9 ++ toolkit/devtools/async-utils.js | 22 +++++ toolkit/devtools/gcli/commands/inject.js | 80 +++++++++++++++ .../gcli/source/lib/gcli/connectors/index.js | 1 + .../devtools/gcli/source/lib/gcli/index.js | 1 + .../gcli/source/lib/gcli/types/union.js | 96 ++++++++++++++++++ 13 files changed, 332 insertions(+) create mode 100644 browser/devtools/commandline/test/browser_cmd_inject.html create mode 100644 browser/devtools/commandline/test/browser_cmd_inject.js create mode 100644 toolkit/devtools/gcli/commands/inject.js create mode 100644 toolkit/devtools/gcli/source/lib/gcli/types/union.js diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 111930505df6..cf407bd67da2 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1363,6 +1363,11 @@ pref("devtools.gcli.hideIntro", false); // How eager are we to show help: never=1, sometimes=2, always=3 pref("devtools.gcli.eagerHelper", 2); +// Alias to the script URLs for inject command. +pref("devtools.gcli.jquerySrc", "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"); +pref("devtools.gcli.lodashSrc", "http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"); +pref("devtools.gcli.underscoreSrc", "http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"); + // Remember the Web Console filters pref("devtools.webconsole.filter.network", true); pref("devtools.webconsole.filter.networkinfo", false); diff --git a/browser/devtools/commandline/commands-index.js b/browser/devtools/commandline/commands-index.js index dba9d84b47b6..59b38b3c8573 100644 --- a/browser/devtools/commandline/commands-index.js +++ b/browser/devtools/commandline/commands-index.js @@ -14,6 +14,7 @@ const commandModules = [ "gcli/commands/cmd", "gcli/commands/cookie", "gcli/commands/csscoverage", + "gcli/commands/inject", "gcli/commands/jsb", "gcli/commands/listen", "gcli/commands/media", diff --git a/browser/devtools/commandline/test/browser.ini b/browser/devtools/commandline/test/browser.ini index 313427ef7947..0da2bc29c5b1 100644 --- a/browser/devtools/commandline/test/browser.ini +++ b/browser/devtools/commandline/test/browser.ini @@ -50,6 +50,9 @@ support-files = browser_cmd_csscoverage_sheetB.css browser_cmd_csscoverage_sheetC.css browser_cmd_csscoverage_sheetD.css +[browser_cmd_inject.js] +support-files = + browser_cmd_inject.html [browser_cmd_csscoverage_util.js] [browser_cmd_jsb.js] support-files = diff --git a/browser/devtools/commandline/test/browser_cmd_inject.html b/browser/devtools/commandline/test/browser_cmd_inject.html new file mode 100644 index 000000000000..ea84be393885 --- /dev/null +++ b/browser/devtools/commandline/test/browser_cmd_inject.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/browser/devtools/commandline/test/browser_cmd_inject.js b/browser/devtools/commandline/test/browser_cmd_inject.js new file mode 100644 index 000000000000..453b10afc1dc --- /dev/null +++ b/browser/devtools/commandline/test/browser_cmd_inject.js @@ -0,0 +1,98 @@ +/* Any copyright is dedicated to the Public Domain. +* http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests that the inject commands works as they should + +const TEST_URI = 'http://example.com/browser/browser/devtools/commandline/'+ + 'test/browser_cmd_inject.html'; + +function test() { + helpers.addTabWithToolbar(TEST_URI, function(options) { + return helpers.audit(options, [ + { + setup: 'inject', + check: { + input: 'inject', + hints: ' ', + markup: 'VVVVVV', + status: 'ERROR' + }, + }, + { + setup: 'inject j', + check: { + input: 'inject j', + hints: 'Query', + markup: 'VVVVVVVI', + status: 'ERROR' + }, + }, + { + setup: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js', + check: { + input: 'inject http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js', + hints: '', + markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV', + status: 'VALID', + args: { + library: { + value: function(library) { + is(library.type, 'string', 'inject type name'); + is(library.string, 'http://example.com/browser/browser/devtools/commandline/test/browser_cmd_inject.js', + 'inject uri data'); + }, + status: 'VALID' + } + } + }, + exec: { + output: [ /http:\/\/example.com\/browser\/browser\/devtools\/commandline\/test\/browser_cmd_inject.js loaded/ ] + } + }, + { + setup: 'inject notauri', + check: { + input: 'inject notauri', + hints: '', + markup: 'VVVVVVVVVVVVVV', + status: 'VALID', + args: { + library: { + value: function(library) { + is(library.type, 'string', 'inject type name'); + is(library.string, 'notauri', 'inject notauri data'); + }, + status: 'VALID' + } + } + }, + exec: { + output: [ /Failed to load notauri - Invalid URI/ ] + } + }, + { + setup: 'inject jQuery', + check: { + input: 'inject jQuery', + hints: '', + markup: 'VVVVVVVVVVVVV', + status: 'VALID', + args: { + library: { + value: function(library) { + is(library.type, 'selection', 'inject type name'); + is(library.selection.name, 'jQuery', 'inject jquery name'); + is(library.selection.src, 'http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js', + 'inject jquery src'); + }, + status: 'VALID' + } + } + }, + exec: { + output: [ /jQuery loaded/ ] + } + }, + ]); + }).then(finish, helpers.handleError); +} diff --git a/browser/devtools/commandline/test/browser_gcli_types.js b/browser/devtools/commandline/test/browser_gcli_types.js index 0561875a1cbf..67d8c897e8b4 100644 --- a/browser/devtools/commandline/test/browser_gcli_types.js +++ b/browser/devtools/commandline/test/browser_gcli_types.js @@ -76,6 +76,9 @@ function forEachType(options, typeSpec, callback) { else if (name === 'remote') { return; } + else if (name === 'union') { + typeSpec.types = [{ name: "string" }]; + } var type = types.createType(typeSpec); var reply = callback(type); @@ -86,6 +89,7 @@ function forEachType(options, typeSpec, callback) { delete typeSpec.data; delete typeSpec.delegateType; delete typeSpec.subtype; + delete typeSpec.types; return value; }); diff --git a/browser/locales/en-US/chrome/browser/devtools/gcli.properties b/browser/locales/en-US/chrome/browser/devtools/gcli.properties index 783d99b70614..2a59f3060542 100644 --- a/browser/locales/en-US/chrome/browser/devtools/gcli.properties +++ b/browser/locales/en-US/chrome/browser/devtools/gcli.properties @@ -177,6 +177,10 @@ helpIntro=GCLI is an experiment to create a highly usable command line for web d # sub-commands. subCommands=Sub-Commands +# LOCALIZATION NOTE: This error message is displayed when the command line is +# cannot find a match for the parse types. +commandParseError=Command line parsing error + # LOCALIZATION NOTE (contextDesc, contextManual, contextPrefixDesc): These # strings are used to describe the 'context' command and its 'prefix' # parameter. See localization comment for 'connect' for an explanation about diff --git a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties index 92fffcd755e9..66aa8350a714 100644 --- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties +++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties @@ -1391,3 +1391,12 @@ mediaEmulateDesc=Emulate a specified CSS media type mediaEmulateManual=View the document as if rendered on a device supporting the given media type, with the relevant CSS rules applied. mediaEmulateType=The media type to emulate mediaResetDesc=Stop emulating a CSS media type + +# LOCALIZATION NOTE (injectDesc, injectManual, injectLibraryDesc, injectLoaded, +# injectFailed) These strings describe the 'inject' commands and all available +# parameters. +injectDesc=Inject common libraries into the page +injectManual=Inject common libraries into the content of the page which can also be accessed from the Firefox console. +injectLibraryDesc=Select the library to inject or enter a valid script URI to inject +injectLoaded=%1$S loaded +injectFailed=Failed to load %1$S - Invalid URI diff --git a/toolkit/devtools/async-utils.js b/toolkit/devtools/async-utils.js index 9e53c93b30ad..ca604a2a0c4a 100644 --- a/toolkit/devtools/async-utils.js +++ b/toolkit/devtools/async-utils.js @@ -53,6 +53,28 @@ exports.asyncOnce = function asyncOnce(func) { }; }; +/** + * Adds an event listener to the given element, and then removes its event + * listener once the event is called, returning the event object as a promise. + * @param nsIDOMElement element + * The DOM element to listen on + * @param String event + * The name of the event type to listen for + * @param Boolean useCapture + * Should we initiate the capture phase? + * @return Promise + * The promise resolved with the event object when the event first + * happens + */ +exports.listenOnce = function listenOnce(element, event, useCapture) { + return new Promise(function(resolve, reject) { + var onEvent = function(ev) { + element.removeEventListener(event, onEvent, useCapture); + resolve(ev); + } + element.addEventListener(event, onEvent, useCapture); + }); +}; /** * Call a function that expects a callback as the last argument and returns a diff --git a/toolkit/devtools/gcli/commands/inject.js b/toolkit/devtools/gcli/commands/inject.js new file mode 100644 index 000000000000..7939677eed9c --- /dev/null +++ b/toolkit/devtools/gcli/commands/inject.js @@ -0,0 +1,80 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { Services } = require("resource://gre/modules/Services.jsm"); +const { listenOnce } = require("devtools/async-utils"); +const gcli = require("gcli/index"); + +exports.items = [ + { + name: "inject", + description: gcli.lookup("injectDesc"), + manual: gcli.lookup("injectManual"), + params: [{ + name: 'library', + type: { + name: "union", + types: [ + { + name: "selection", + lookup: [ + { + name: "jQuery", + value: { + name: "jQuery", + src: Services.prefs.getCharPref("devtools.gcli.jquerySrc") + } + }, + { + name: "lodash", + value: { + name: "lodash", + src: Services.prefs.getCharPref("devtools.gcli.lodashSrc") + } + }, + { + name: "underscore", + value: { + name: "underscore", + src: Services.prefs.getCharPref("devtools.gcli.underscoreSrc") + } + } + ] + }, + { + name: "string" + } + ] + }, + description: gcli.lookup("injectLibraryDesc") + }], + exec: function*(args, context) { + let document = context.environment.document; + let library = args.library; + let name = (library.type === "selection") ? + library.selection.name : library.string; + let src = (library.type === "selection") ? + library.selection.src : library.string; + + try { + // Check if URI is valid + Services.io.newURI(src, null, null); + } catch(e) { + return gcli.lookupFormat("injectFailed", [name]); + } + + let newSource = document.createElement("script"); + newSource.setAttribute("src", src); + + let loadPromise = listenOnce(newSource, "load"); + document.head.appendChild(newSource); + + yield loadPromise; + + return gcli.lookupFormat("injectLoaded", [name]); + } + } +]; diff --git a/toolkit/devtools/gcli/source/lib/gcli/connectors/index.js b/toolkit/devtools/gcli/source/lib/gcli/connectors/index.js index 64dee6d4c036..bbe48bd9b4f7 100644 --- a/toolkit/devtools/gcli/source/lib/gcli/connectors/index.js +++ b/toolkit/devtools/gcli/source/lib/gcli/connectors/index.js @@ -53,6 +53,7 @@ var items = [ require('../types/resource').items, require('../types/setting').items, require('../types/string').items, + require('../types/union').items, require('../fields/delegate').items, require('../fields/selection').items, diff --git a/toolkit/devtools/gcli/source/lib/gcli/index.js b/toolkit/devtools/gcli/source/lib/gcli/index.js index 4518429e95c7..e6483f37a9b0 100644 --- a/toolkit/devtools/gcli/source/lib/gcli/index.js +++ b/toolkit/devtools/gcli/source/lib/gcli/index.js @@ -48,6 +48,7 @@ var items = [ require('./types/resource').items, require('./types/setting').items, require('./types/string').items, + require('./types/union').items, require('./fields/delegate').items, require('./fields/selection').items, diff --git a/toolkit/devtools/gcli/source/lib/gcli/types/union.js b/toolkit/devtools/gcli/source/lib/gcli/types/union.js new file mode 100644 index 000000000000..ee5d766f6478 --- /dev/null +++ b/toolkit/devtools/gcli/source/lib/gcli/types/union.js @@ -0,0 +1,96 @@ +/* + * Copyright 2014, Mozilla Foundation and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +var Promise = require('../util/promise').Promise; +var l10n = require('../util/l10n'); +var centralTypes = require("./types").centralTypes; +var Conversion = require("./types").Conversion; +var Status = require("./types").Status; + +exports.items = [ + { + // The union type allows for a combination of different parameter types. + item: "type", + name: "union", + + constructor: function() { + // Get the properties of the type. The last object in the list of types + // should always be a string type. + this.types = this.types.map(function(typeData) { + typeData.type = centralTypes.createType(typeData); + typeData.lookup = typeData.lookup; + return typeData; + }); + }, + + stringify: function(value, context) { + if (value == null) { + return ""; + } + + var type = this.types.find(function(typeData) { + return typeData.name == value.type; + }).type; + + return type.stringify(value[value.type], context); + }, + + parse: function(arg, context) { + // Try to parse the given argument in the provided order of the parameter + // types. Returns a promise containing the Conversion of the value that + // was parsed. + var self = this; + + var onError = function(i) { + if (i >= self.types.length) { + return Promise.reject(new Conversion(undefined, arg, Status.ERROR, + l10n.lookup("commandParseError"))); + } else { + return tryNext(i + 1); + } + }; + + var tryNext = function(i) { + var type = self.types[i].type; + + try { + return type.parse(arg, context).then(function(conversion) { + if (conversion.getStatus() === Status.VALID || + conversion.getStatus() === Status.INCOMPLETE) { + // Converts the conversion value of the union type to an + // object that identifies the current working type and the + // data associated with it + if (conversion.value) { + var oldConversionValue = conversion.value; + conversion.value = { type: type.name }; + conversion.value[type.name] = oldConversionValue; + } + return conversion; + } else { + return onError(i); + } + }); + } catch(e) { + return onError(i); + } + }; + + return Promise.resolve(tryNext(0)); + }, + } +]; From 882218a904a0fe6c289c621bb18ac1a5d2ab8c57 Mon Sep 17 00:00:00 2001 From: Tim Nguyen Date: Sun, 8 Jun 2014 00:26:00 -0400 Subject: [PATCH 37/52] Bug 1022290 - Add HDPI asset for computed view arrow. r=bgrins --- browser/themes/linux/jar.mn | 1 + browser/themes/osx/jar.mn | 1 + .../themes/shared/devtools/computedview.css | 18 ++++++++++++------ .../themes/shared/devtools/images/arrow-e.png | Bin 177 -> 168 bytes .../shared/devtools/images/arrow-e@2x.png | Bin 0 -> 417 bytes browser/themes/windows/jar.mn | 2 ++ 6 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 browser/themes/shared/devtools/images/arrow-e@2x.png diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn index 2bd1967915e0..cf5c83a02e1e 100644 --- a/browser/themes/linux/jar.mn +++ b/browser/themes/linux/jar.mn @@ -318,6 +318,7 @@ browser.jar: skin/classic/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css) skin/classic/browser/devtools/computedview.css (../shared/devtools/computedview.css) skin/classic/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png) + skin/classic/browser/devtools/arrow-e@2x.png (../shared/devtools/images/arrow-e@2x.png) skin/classic/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css) skin/classic/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png) skin/classic/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css) diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn index 0acf716e2aa9..383de7cb73d3 100644 --- a/browser/themes/osx/jar.mn +++ b/browser/themes/osx/jar.mn @@ -436,6 +436,7 @@ browser.jar: skin/classic/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css) skin/classic/browser/devtools/computedview.css (../shared/devtools/computedview.css) skin/classic/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png) + skin/classic/browser/devtools/arrow-e@2x.png (../shared/devtools/images/arrow-e@2x.png) skin/classic/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css) skin/classic/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png) skin/classic/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css) diff --git a/browser/themes/shared/devtools/computedview.css b/browser/themes/shared/devtools/computedview.css index bcbdf3b6f438..cbaec23a9dfd 100644 --- a/browser/themes/shared/devtools/computedview.css +++ b/browser/themes/shared/devtools/computedview.css @@ -51,23 +51,29 @@ body { outline: 0; } +.property-value, .other-property-value { + background-image: url(arrow-e.png); + background-repeat: no-repeat; + background-size: 5px 8px; +} + +@media (min-resolution: 2dppx) { + .property-value, .other-property-value { + background-image: url(arrow-e@2x.png); + } +} + .property-value { width: 100%; overflow-x: hidden; text-overflow: ellipsis; white-space: nowrap; - background-image: url(arrow-e.png); - background-repeat: no-repeat; - background-size: 5px 8px; background-position: 2px center; padding-left: 10px; outline: 0; } .other-property-value { - background-image: url(arrow-e.png); - background-repeat: no-repeat; - background-size: 5px 8px; background-position: left center; padding-left: 8px; } diff --git a/browser/themes/shared/devtools/images/arrow-e.png b/browser/themes/shared/devtools/images/arrow-e.png index 09691bc5e540079d8b83efbd4aa78f2b71e03d95..cfa950a1f69e7cdcfa640aa7cabbab08503704a2 100644 GIT binary patch delta 140 zcmV;70CWGb0jL3xB!6#7L_t&t*Hw-&3V<*SMXSa*r3bxiL%Q&@wQ2wW002ovP6b4+LSTZsk~pgX delta 149 zcmV;G0BZlJ0kHv)B!75GL_t&tTVt3sX9)`s=KwMD|Ns9PK$u~|tR*=sw;ad;(GzAa zW&{f^-ME(ph;u-=XZpe%upo$7uyz*<5a)n!$K-iAV8NCNb697s+@1r&4D~&;SR49g z=S*F?6^y~!Yr1CSOjx)Ph9MU9%v;Y4#5o`u<|F_y?q1WHoeqGy00000NkvXXu0mjf Dcc(w7 diff --git a/browser/themes/shared/devtools/images/arrow-e@2x.png b/browser/themes/shared/devtools/images/arrow-e@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c628ca0a5c188039d6a15e7fbdd7109ae4989f3a GIT binary patch literal 417 zcmV;S0bc%zP)|`5y|4Huj^OVxvwJ7RR@7VV$8GvFqAYpoK znr1oyg%CD$=g#&QK)pH0*aoTHyTBN4Cop558R{>Kw!Z{23;vG}|X{b41)ZwCpjws01nsISNY~$#zXnuK}o* z2W8oSa=m-72D)6^nIb%xLX@&G1SEA2W2jKa+_OxO8jjVR$tqRn<2W|DP{v$IY$Fto zQY;@LtlE>)*kK~{AT-gVWPn6GkgYK^sDB>2o*Pli-B+5Z2s(h_h0qV-`=z2xcVc_x z1)M2V+j&uUS5PG0ZH>;>zjsuq8QzuH^@_rOKZrNK(iL^I_gnoNpisraSuie-00000 LNkvXXu0mjfV)D8a literal 0 HcmV?d00001 diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn index 582457dc49dd..bb3a29dd8cd1 100644 --- a/browser/themes/windows/jar.mn +++ b/browser/themes/windows/jar.mn @@ -355,6 +355,7 @@ browser.jar: skin/classic/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css) skin/classic/browser/devtools/computedview.css (../shared/devtools/computedview.css) skin/classic/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png) + skin/classic/browser/devtools/arrow-e@2x.png (../shared/devtools/images/arrow-e@2x.png) skin/classic/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css) skin/classic/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png) skin/classic/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css) @@ -758,6 +759,7 @@ browser.jar: skin/classic/aero/browser/devtools/font-inspector.css (../shared/devtools/font-inspector.css) skin/classic/aero/browser/devtools/computedview.css (../shared/devtools/computedview.css) skin/classic/aero/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e.png) + skin/classic/aero/browser/devtools/arrow-e.png (../shared/devtools/images/arrow-e@2x.png) skin/classic/aero/browser/devtools/projecteditor/projecteditor.css (../shared/devtools/projecteditor/projecteditor.css) skin/classic/aero/browser/devtools/projecteditor/file-icons-sheet@2x.png (../shared/devtools/projecteditor/file-icons-sheet@2x.png) skin/classic/aero/browser/devtools/app-manager/connection-footer.css (../shared/devtools/app-manager/connection-footer.css) From f7cb217dac63cef9516172e07216574d794998f1 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Mon, 9 Jun 2014 13:24:13 -0700 Subject: [PATCH 38/52] Bug 1021163 - Animate tab close upwards in horizontal tabs tray. r=liuche --- mobile/android/base/tabspanel/TabsTray.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/base/tabspanel/TabsTray.java b/mobile/android/base/tabspanel/TabsTray.java index 75bc3bfebe13..2f0aad781f18 100644 --- a/mobile/android/base/tabspanel/TabsTray.java +++ b/mobile/android/base/tabspanel/TabsTray.java @@ -151,7 +151,7 @@ class TabsTray extends TwoWayView @Override public void onClick(View v) { TabRow tab = (TabRow) v.getTag(); - final int pos = (isVertical() ? tab.info.getWidth() : tab.info.getHeight()); + final int pos = (isVertical() ? tab.info.getWidth() : 0 - tab.info.getHeight()); animateClose(tab.info, pos); } }; From 982130f0c5c3872d24fc7a06238c008183419654 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Mon, 9 Jun 2014 13:24:16 -0700 Subject: [PATCH 39/52] Bug 1009586 - Remove unused string. r=liuche --- mobile/android/base/locales/en-US/android_strings.dtd | 1 - mobile/android/base/strings.xml.in | 1 - 2 files changed, 2 deletions(-) diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index 83b6134259ed..98bf3760756e 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -109,7 +109,6 @@ -