From 39f926dab026665dd9a18662f21db8afa4de2e75 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 23 Aug 2018 13:07:36 +0900 Subject: [PATCH 01/80] Bug 1417646 - Add llvm-dsynutil/ into PATH. r=glandium Differential Revision: https://phabricator.services.mozilla.com/D4041 --- build/macosx/cross-mozconfig.common | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/macosx/cross-mozconfig.common b/build/macosx/cross-mozconfig.common index 46d71289fed2..5955e850fcf1 100644 --- a/build/macosx/cross-mozconfig.common +++ b/build/macosx/cross-mozconfig.common @@ -10,6 +10,9 @@ if [ "x$IS_NIGHTLY" = "xyes" ]; then fi . "$topsrcdir/build/mozconfig.common" +# Rust requires dsymutil into PATH +mk_add_options "export PATH=$topsrcdir/llvm-dsymutil/bin:$PATH" + # ld needs libLTO.so from llvm mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/clang/lib" From eb72babf41fce45d4f0ab26bc8243b8ec36ffc19 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 5 Jul 2018 07:19:24 -0400 Subject: [PATCH 02/80] bug 1417646 - build geckodriver in cross-compile builds. r=ato With patches from other bugs in place to use the right C compiler and cflags, we can enable geckodriver on cross-compiles for macOS. MozReview-Commit-ID: 5wqBiA6UCf --- build/unix/mozconfig.linux32 | 7 ------- toolkit/moz.configure | 9 ++++++--- toolkit/toolkit.mozbuild | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/build/unix/mozconfig.linux32 b/build/unix/mozconfig.linux32 index 47c4ce3dbdd2..8da778465d97 100644 --- a/build/unix/mozconfig.linux32 +++ b/build/unix/mozconfig.linux32 @@ -6,10 +6,3 @@ CFLAGS="$CFLAGS -march=pentium-m -msse -msse2 -mfpmath=sse" CXXFLAGS="$CXXFLAGS -march=pentium-m -msse -msse2 -mfpmath=sse" ac_add_options --target=i686-pc-linux - -# The linux32 builds are effectively cross-compilations, and geckodriver -# is not enabled by default on cross-compilations, because in most cases, -# the target is not something we can run binaries of, and geckodriver -# is a target binary instead of a host binary. But for linux32, we actually -# can run the target binaries, so we can manually enable geckodriver. -ac_add_options --enable-geckodriver diff --git a/toolkit/moz.configure b/toolkit/moz.configure index 8dab75fe6bd8..85551e7739d9 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -907,9 +907,11 @@ option('--enable-geckodriver', help='Enable WebDriver implementation') @depends('--enable-geckodriver', 'MOZ_AUTOMATION', compile_environment, + target, cross_compiling, - hazard_analysis) -def geckodriver(enable, automation, compile_env, cross_compile, hazard): + hazard_analysis, + asan) +def geckodriver(enable, automation, compile_env, target, cross_compile, hazard, asan): """ geckodriver is implied on supported platforms when MOZ_AUTOMATION is set, but we also provide the --enable-geckodriver option for @@ -927,7 +929,8 @@ def geckodriver(enable, automation, compile_env, cross_compile, hazard): return True if enable.origin == 'default': - broken_platforms = cross_compile or hazard + # Bug 1441656 for Android. + broken_platforms = hazard or target.os == 'Android' or (asan and cross_compile) if automation and compile_env and not broken_platforms: return True diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index d8337d0de471..4a0e5f17271f 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -165,7 +165,7 @@ if CONFIG['ENABLE_MARIONETTE']: '/testing/marionette', ] -if CONFIG['ENABLE_GECKODRIVER']: +if CONFIG['ENABLE_GECKODRIVER'] and not CONFIG['MOZ_TSAN']: DIRS += ['/testing/geckodriver'] DIRS += [ From 3b7a466c3a5ea52c1d58d5f9a3ccf5d34ab20f83 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Mon, 3 Sep 2018 15:18:12 +0200 Subject: [PATCH 03/80] Bug 1440468 - Proxied functions can't be passed to Function.prototype.toString.call(). r=anba --HG-- extra : rebase_source : 072f9a5fae3b19e98be278db0c28027473189f24 extra : histedit_source : fd500751ba230f29c8b779a9a410a441710f0dd8 --- js/src/jit-test/tests/basic/bug807623.js | 7 +------ js/src/jit-test/tests/proxy/function-toString.js | 8 ++++---- js/src/proxy/BaseProxyHandler.cpp | 5 +++-- js/src/proxy/ScriptedProxyHandler.cpp | 6 +++--- js/src/tests/jstests.list | 13 ------------- 5 files changed, 11 insertions(+), 28 deletions(-) diff --git a/js/src/jit-test/tests/basic/bug807623.js b/js/src/jit-test/tests/basic/bug807623.js index ce16ffd41719..35c34d3cb39f 100644 --- a/js/src/jit-test/tests/basic/bug807623.js +++ b/js/src/jit-test/tests/basic/bug807623.js @@ -3,12 +3,7 @@ var functionProxy = new Proxy(function() {}, {}); assertEq(Object.prototype.toString.call(objectProxy), '[object Object]'); assertEq(Object.prototype.toString.call(functionProxy), '[object Function]'); -try { - Function.prototype.toString.call(functionProxy); - assertEq(true, false); -} catch (e) { - assertEq(!!/incompatible/.exec(e), true); -} + try { Function.prototype.toString.call(objectProxy); assertEq(true, false); diff --git a/js/src/jit-test/tests/proxy/function-toString.js b/js/src/jit-test/tests/proxy/function-toString.js index cedcf552a412..4aca5c907eac 100644 --- a/js/src/jit-test/tests/proxy/function-toString.js +++ b/js/src/jit-test/tests/proxy/function-toString.js @@ -1,10 +1,10 @@ load(libdir + 'asserts.js'); -// Function.prototype.toString doesn't accept ES6 proxies. +var nativeCode = "function () {\n [native code]\n}"; var proxy = new Proxy(function() {}, {}); -assertThrowsInstanceOf(() => Function.prototype.toString.call(proxy), TypeError); +assertEq(Function.prototype.toString.call(proxy), nativeCode); var o = Proxy.revocable(function() {}, {}); -assertThrowsInstanceOf(() => Function.prototype.toString.call(o.proxy), TypeError); +assertEq(Function.prototype.toString.call(o.proxy), nativeCode); o.revoke(); -assertThrowsInstanceOf(() => Function.prototype.toString.call(o.proxy), TypeError); +assertEq(Function.prototype.toString.call(o.proxy), nativeCode); diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index c8eca3e524b4..c44ed7b553c2 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -310,8 +310,9 @@ BaseProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSourc { if (proxy->isCallable()) return JS_NewStringCopyZ(cx, "function () {\n [native code]\n}"); - RootedValue v(cx, ObjectValue(*proxy)); - ReportIsNotFunction(cx, v); + + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_toString_str, "object"); return nullptr; } diff --git a/js/src/proxy/ScriptedProxyHandler.cpp b/js/src/proxy/ScriptedProxyHandler.cpp index 89442d9b3a50..79a996a48cf4 100644 --- a/js/src/proxy/ScriptedProxyHandler.cpp +++ b/js/src/proxy/ScriptedProxyHandler.cpp @@ -1264,9 +1264,9 @@ ScriptedProxyHandler::className(JSContext* cx, HandleObject proxy) const JSString* ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, - js_Function_str, js_toString_str, "object"); - return nullptr; + // The BaseProxyHandler has the desired behavior: Throw for non-callable, + // otherwise return [native code]. + return BaseProxyHandler::fun_toString(cx, proxy, isToSource); } RegExpShared* diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list index fee51686f4ff..31b287ce3d89 100644 --- a/js/src/tests/jstests.list +++ b/js/src/tests/jstests.list @@ -414,19 +414,6 @@ skip script test262/annexB/built-ins/Function/createdynfn-html-close-comment-par # https://bugzilla.mozilla.org/show_bug.cgi?id=1334813 skip script test262/built-ins/DataView/length.js -# https://bugzilla.mozilla.org/show_bug.cgi?id=1440468 -skip script test262/built-ins/Function/prototype/toString/proxy.js -skip script test262/built-ins/Function/prototype/toString/proxy-async-generator-function.js -skip script test262/built-ins/Function/prototype/toString/proxy-class.js -skip script test262/built-ins/Function/prototype/toString/proxy-async-method-definition.js -skip script test262/built-ins/Function/prototype/toString/proxy-arrow-function.js -skip script test262/built-ins/Function/prototype/toString/proxy-async-generator-method-definition.js -skip script test262/built-ins/Function/prototype/toString/proxy-async-function.js -skip script test262/built-ins/Function/prototype/toString/proxy-bound-function.js -skip script test262/built-ins/Function/prototype/toString/proxy-method-definition.js -skip script test262/built-ins/Function/prototype/toString/proxy-function-expression.js -skip script test262/built-ins/Function/prototype/toString/proxy-generator-function.js - # https://bugzilla.mozilla.org/show_bug.cgi?id=1462741 skip script test262/built-ins/Function/prototype/toString/well-known-intrinsic-object-functions.js From 50432947586310ed1e3437e56952b788d01446d5 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Mon, 3 Sep 2018 23:47:56 +0200 Subject: [PATCH 04/80] Bug 1440468 - Fix devtools test for new Function.prototype.toString behavior. r=yulia --HG-- extra : rebase_source : cf924cd850c094d782aefc3037a648082f709695 extra : histedit_source : 0055b621cbfbb943eb6229a6ad3800b3deaa99d5 --- devtools/server/tests/unit/test_objectgrips-21.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devtools/server/tests/unit/test_objectgrips-21.js b/devtools/server/tests/unit/test_objectgrips-21.js index 2c6b134e5bdc..209d302deb8b 100644 --- a/devtools/server/tests/unit/test_objectgrips-21.js +++ b/devtools/server/tests/unit/test_objectgrips-21.js @@ -178,8 +178,8 @@ const nullPrincipalTests = [{ property: descriptor({value: "Error"}), afterTest: `trapDidRun === false`, }, { - // Like the previous test, but now the object has a Function class. - string: "[object Function]", + // Like the previous test, but now the object is a callable Proxy. + string: "function () {\n [native code]\n}", isFunction: true, hasPreview: false, code: ` From af073d5466aa21e3fb2ec0a816e543f0f9ccb262 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 4 Sep 2018 10:04:51 +0100 Subject: [PATCH 05/80] Bug 1488173 - Define constructor property last in DefineConstructorAndPrototype r=jandem --- js/src/vm/JSObject.cpp | 46 ++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index 1ff089cf9873..343485b72a8c 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -1831,15 +1831,6 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b) return true; } -static bool -DefineStandardSlot(JSContext* cx, HandleObject obj, JSAtom* atom, - HandleValue v, uint32_t attrs, bool& named) -{ - RootedId id(cx, AtomToId(atom)); - named = DefineDataProperty(cx, obj, id, v, attrs); - return named; -} - static void SetClassObject(JSObject* obj, JSProtoKey key, JSObject* cobj, JSObject* proto) { @@ -1898,9 +1889,15 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H if (!proto) return nullptr; + /* + * Whether we need to define a constructor property on |obj| and which + * attributes to use. + */ + bool defineConstructorProperty = false; + uint32_t propertyAttrs = 0; + /* After this point, control must exit via label bad or out. */ RootedNativeObject ctor(cx); - bool named = false; bool cached = false; if (!constructor) { /* @@ -1912,12 +1909,10 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H if (!(clasp->flags & JSCLASS_IS_ANONYMOUS) || !obj->is() || key == JSProto_Null) { - uint32_t attrs = (clasp->flags & JSCLASS_IS_ANONYMOUS) - ? JSPROP_READONLY | JSPROP_PERMANENT - : 0; - RootedValue value(cx, ObjectValue(*proto)); - if (!DefineStandardSlot(cx, obj, atom, value, attrs, named)) - goto bad; + defineConstructorProperty = true; + propertyAttrs = (clasp->flags & JSCLASS_IS_ANONYMOUS) + ? JSPROP_READONLY | JSPROP_PERMANENT + : 0; } ctor = proto; @@ -1936,9 +1931,8 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H cached = true; } - RootedValue value(cx, ObjectValue(*fun)); - if (!DefineStandardSlot(cx, obj, atom, value, 0, named)) - goto bad; + defineConstructorProperty = true; + propertyAttrs = 0; /* * Optionally construct the prototype object, before the class has @@ -1961,6 +1955,13 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H goto bad; } + if (defineConstructorProperty) { + RootedId id(cx, AtomToId(atom)); + RootedValue value(cx, ObjectValue(*ctor)); + if (!DefineDataProperty(cx, obj, id, value, propertyAttrs)) + goto bad; + } + /* If this is a standard class, cache its prototype. */ if (!cached && key != JSProto_Null) SetClassObject(obj, key, ctor, proto); @@ -1970,13 +1971,6 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H return proto; bad: - if (named) { - ObjectOpResult ignored; - RootedId id(cx, AtomToId(atom)); - - // XXX FIXME - absurd to call this here; instead define the property last. - DeleteProperty(cx, obj, id, ignored); - } if (cached) ClearClassObject(obj, key); return nullptr; From 1a2b3f08044a8573acf7be40aa036f441ac38ea6 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 4 Sep 2018 10:05:17 +0100 Subject: [PATCH 06/80] Bug 1488227 - Don't set shell exit code during OOM testing r=nbp --- js/src/jit-test/tests/debug/bug-1260725.js | 4 +--- js/src/jit-test/tests/debug/bug1251919.js | 4 +--- js/src/jit-test/tests/debug/bug1254123.js | 4 +--- js/src/jit-test/tests/debug/bug1254190.js | 4 ++-- js/src/jit-test/tests/debug/bug1254578.js | 4 ++-- js/src/jit-test/tests/debug/bug1264961.js | 6 ++---- js/src/jit-test/tests/debug/bug1272908.js | 9 ++++++--- js/src/jit-test/tests/debug/bug1404710.js | 3 +-- js/src/shell/js.cpp | 11 +++++++++-- 9 files changed, 25 insertions(+), 24 deletions(-) diff --git a/js/src/jit-test/tests/debug/bug-1260725.js b/js/src/jit-test/tests/debug/bug-1260725.js index ee7539ca60bf..3662b34e6399 100644 --- a/js/src/jit-test/tests/debug/bug-1260725.js +++ b/js/src/jit-test/tests/debug/bug-1260725.js @@ -1,7 +1,5 @@ -// |jit-test| error: out of memory - if (!('oomTest' in this)) - throw new Error("out of memory"); + quit() var dbg = new Debugger; dbg.onNewGlobalObject = function(global) { diff --git a/js/src/jit-test/tests/debug/bug1251919.js b/js/src/jit-test/tests/debug/bug1251919.js index 02090bfeec37..4023445901f5 100644 --- a/js/src/jit-test/tests/debug/bug1251919.js +++ b/js/src/jit-test/tests/debug/bug1251919.js @@ -1,7 +1,5 @@ -// |jit-test| error: out of memory - if (!('oomTest' in this)) - throw new Error("out of memory"); + quit(); // jsfunfuzz-generated fullcompartmentchecks(true); diff --git a/js/src/jit-test/tests/debug/bug1254123.js b/js/src/jit-test/tests/debug/bug1254123.js index 39ff166a7477..821247709399 100644 --- a/js/src/jit-test/tests/debug/bug1254123.js +++ b/js/src/jit-test/tests/debug/bug1254123.js @@ -1,7 +1,5 @@ -// |jit-test| error: boom - if (!('oomTest' in this)) - throw new Error("boom"); + quit(); evaluate(` function ERROR(msg) { diff --git a/js/src/jit-test/tests/debug/bug1254190.js b/js/src/jit-test/tests/debug/bug1254190.js index bdca38cbe28b..26822dcd0113 100644 --- a/js/src/jit-test/tests/debug/bug1254190.js +++ b/js/src/jit-test/tests/debug/bug1254190.js @@ -1,7 +1,7 @@ -// |jit-test| error: out of memory; slow; +// |jit-test| slow if (!('oomTest' in this)) - throw new Error("out of memory"); + quit(); var g = newGlobal(); var dbg = new Debugger(g); diff --git a/js/src/jit-test/tests/debug/bug1254578.js b/js/src/jit-test/tests/debug/bug1254578.js index 4f28f67ab44d..423fd255bd4d 100644 --- a/js/src/jit-test/tests/debug/bug1254578.js +++ b/js/src/jit-test/tests/debug/bug1254578.js @@ -1,7 +1,7 @@ -// |jit-test| error:ReferenceError; slow +// |jit-test| slow if (!('oomTest' in this)) - throw (new ReferenceError); + quit(); var g = newGlobal(); g.debuggeeGlobal = this; diff --git a/js/src/jit-test/tests/debug/bug1264961.js b/js/src/jit-test/tests/debug/bug1264961.js index e53b02a96467..30575d7db19a 100644 --- a/js/src/jit-test/tests/debug/bug1264961.js +++ b/js/src/jit-test/tests/debug/bug1264961.js @@ -20,9 +20,7 @@ function loadFile(lfVarx) { var k = 0; oomTest(function() { // In practice a crash occurs before iteration 4000. - if (k++ > 4000) - quit(); - eval(lfVarx); + if (k++ <= 4000) + eval(lfVarx); }) } - diff --git a/js/src/jit-test/tests/debug/bug1272908.js b/js/src/jit-test/tests/debug/bug1272908.js index 5470378fed15..f2d120539b7e 100644 --- a/js/src/jit-test/tests/debug/bug1272908.js +++ b/js/src/jit-test/tests/debug/bug1272908.js @@ -1,12 +1,15 @@ -// |jit-test| error: out of memory; slow; +// |jit-test| slow + +if (!('oomTest' in this)) + quit(); // Adapted from randomly chosen test: js/src/jit-test/tests/modules/bug-1233915.js g = newGlobal(); g.parent = this; g.eval("(" + function() { - Debugger(parent).onExceptionUnwind = function(frame) + Debugger(parent).onExceptionUnwind = function(frame) { frame.eval("") -} + ")()"); + } } + ")()"); // Adapted from randomly chosen test: js/src/jit-test/tests/debug/bug1254123.js function ERROR(msg) { throw new Error("boom"); diff --git a/js/src/jit-test/tests/debug/bug1404710.js b/js/src/jit-test/tests/debug/bug1404710.js index a4a88ae5e1f5..6f8224f1c326 100644 --- a/js/src/jit-test/tests/debug/bug1404710.js +++ b/js/src/jit-test/tests/debug/bug1404710.js @@ -1,6 +1,5 @@ -// |jit-test| error:InternalError if (!('stackTest' in this)) - throw InternalError(); + quit(); stackTest(new Function(` var g = newGlobal(); var dbg = new Debugger(g); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 60d7b465bd9d..4944f7352d5b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -8243,12 +8243,19 @@ js::shell::AutoReportException::~AutoReportException() savedExc.restore(); } + JS_ClearPendingException(cx); + +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + // Don't quit the shell if an unhandled exception is reported during OOM + // testing. + if (cx->runningOOMTest) + return; +#endif + if (report.report()->errorNumber == JSMSG_OUT_OF_MEMORY) sc->exitCode = EXITCODE_OUT_OF_MEMORY; else sc->exitCode = EXITCODE_RUNTIME_ERROR; - - JS_ClearPendingException(cx); } void From 92a1dd14a23610d47e45393c85b5f95a080253cf Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 3 Sep 2018 17:30:55 +0200 Subject: [PATCH 07/80] Bug 1484905 - Don't mark MGetFirstDollarIndex as movable. r=arai Differential Revision: https://phabricator.services.mozilla.com/D4879 --HG-- extra : rebase_source : f897bf525e37e16abd6bb6669d5a711a7c8c73bd extra : amend_source : 9dffa1a44ee0efe596d0294a1a9958a8a454e2e8 --- js/src/jit-test/tests/ion/bug1484905.js | 4 ++++ js/src/jit/MIR.h | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/ion/bug1484905.js diff --git a/js/src/jit-test/tests/ion/bug1484905.js b/js/src/jit-test/tests/ion/bug1484905.js new file mode 100644 index 000000000000..3a819ea8153d --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1484905.js @@ -0,0 +1,4 @@ +// |jit-test| --ion-limit-script-size=off; --ion-gvn=off +for (var i = 0; i < 1; ++i) { + "".replace(/x/, "").replace(/y/, "12"); +} diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 6981e1abc935..076b2f75d4da 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7589,7 +7589,10 @@ class MGetFirstDollarIndex : MUnaryInstruction(classOpcode, str) { setResultType(MIRType::Int32); - setMovable(); + + // Codegen assumes string length > 0. Don't allow LICM to move this + // before the .length > 1 check in RegExpReplace in RegExp.js. + MOZ_ASSERT(!isMovable()); } public: From e520af2423d86ef675f5f996363177a3f817f30d Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 4 Sep 2018 13:35:16 +0300 Subject: [PATCH 08/80] Bug 1488359 - Inline GetPrevious/NextElementSibling, r=emilio --- dom/base/Element.h | 37 ++++++++++++++++++++++++++++++++++--- dom/base/nsINode.cpp | 28 ---------------------------- dom/base/nsINode.h | 4 ++-- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/dom/base/Element.h b/dom/base/Element.h index 0688a1f36992..e9493af75ecf 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -2044,23 +2044,54 @@ Element::AttrValueIs(int32_t aNameSpaceID, } // namespace dom } // namespace mozilla -inline mozilla::dom::Element* nsINode::AsElement() +inline mozilla::dom::Element* +nsINode::AsElement() { MOZ_ASSERT(IsElement()); return static_cast(this); } -inline const mozilla::dom::Element* nsINode::AsElement() const +inline const mozilla::dom::Element* +nsINode::AsElement() const { MOZ_ASSERT(IsElement()); return static_cast(this); } -inline mozilla::dom::Element* nsINode::GetParentElement() const +inline mozilla::dom::Element* +nsINode::GetParentElement() const { return mozilla::dom::Element::FromNodeOrNull(mParent); } +inline mozilla::dom::Element* +nsINode::GetPreviousElementSibling() const +{ + nsIContent* previousSibling = GetPreviousSibling(); + while (previousSibling) { + if (previousSibling->IsElement()) { + return previousSibling->AsElement(); + } + previousSibling = previousSibling->GetPreviousSibling(); + } + + return nullptr; +} + +inline mozilla::dom::Element* +nsINode::GetNextElementSibling() const +{ + nsIContent* nextSibling = GetNextSibling(); + while (nextSibling) { + if (nextSibling->IsElement()) { + return nextSibling->AsElement(); + } + nextSibling = nextSibling->GetNextSibling(); + } + + return nullptr; +} + /** * Macros to implement Clone(). _elementName is the class for which to implement * Clone. diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 78f4427201e0..affa9d17be7f 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1571,34 +1571,6 @@ nsINode::ComputeIndexOf(const nsINode* aChild) const return -1; } -Element* -nsINode::GetPreviousElementSibling() const -{ - nsIContent* previousSibling = GetPreviousSibling(); - while (previousSibling) { - if (previousSibling->IsElement()) { - return previousSibling->AsElement(); - } - previousSibling = previousSibling->GetPreviousSibling(); - } - - return nullptr; -} - -Element* -nsINode::GetNextElementSibling() const -{ - nsIContent* nextSibling = GetNextSibling(); - while (nextSibling) { - if (nextSibling->IsElement()) { - return nextSibling->AsElement(); - } - nextSibling = nextSibling->GetNextSibling(); - } - - return nullptr; -} - static already_AddRefed GetNodeFromNodeOrString(const OwningNodeOrString& aNode, nsIDocument* aDocument) diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 44981c89a827..533ba35a21b6 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1836,8 +1836,8 @@ public: } // ChildNode methods - mozilla::dom::Element* GetPreviousElementSibling() const; - mozilla::dom::Element* GetNextElementSibling() const; + inline mozilla::dom::Element* GetPreviousElementSibling() const; + inline mozilla::dom::Element* GetNextElementSibling() const; MOZ_CAN_RUN_SCRIPT void Before(const Sequence& aNodes, ErrorResult& aRv); From 6f702cee0c39c91a4971ede03551efd4e436c088 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Tue, 4 Sep 2018 14:20:21 +0200 Subject: [PATCH 09/80] Bug 1488395 - Fix ifdefs around a nightly-only feature. r=me --- js/src/wasm/WasmTextToBinary.cpp | 2 ++ js/src/wasm/WasmValidate.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp index 6f78c29758bd..fa215606a817 100644 --- a/js/src/wasm/WasmTextToBinary.cpp +++ b/js/src/wasm/WasmTextToBinary.cpp @@ -1176,8 +1176,10 @@ WasmTokenStream::next() break; case 'g': +#ifdef ENABLE_WASM_GC if (consume(u"gc_feature_opt_in")) return WasmToken(WasmToken::GcFeatureOptIn, begin, cur_); +#endif if (consume(u"get_global")) return WasmToken(WasmToken::GetGlobal, begin, cur_); if (consume(u"get_local")) diff --git a/js/src/wasm/WasmValidate.h b/js/src/wasm/WasmValidate.h index dbab1135d7d5..678363c4bdd9 100644 --- a/js/src/wasm/WasmValidate.h +++ b/js/src/wasm/WasmValidate.h @@ -139,13 +139,13 @@ struct ModuleEnvironment size_t numFuncDefs() const { return funcTypes.length() - funcImportGlobalDataOffsets.length(); } -#ifdef ENABLE_WASM_GC HasGcTypes gcTypesEnabled() const { +#ifdef ENABLE_WASM_GC if (gcTypesConfigured == HasGcTypes::True) return gcFeatureOptIn; +#endif return HasGcTypes::False; } -#endif bool usesMemory() const { return memoryUsage != MemoryUsage::None; } From de10473139945d33b9e75ca814436d118385d3fe Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 14:36:34 +0100 Subject: [PATCH 10/80] Bug 1487989: webdriver: deref matched expressions; r=whimboo Instead of accessing each variant using a reference, we should dereference the matched expression when possible. --- testing/webdriver/src/capabilities.rs | 2 +- testing/webdriver/src/command.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/webdriver/src/capabilities.rs b/testing/webdriver/src/capabilities.rs index ff1adff0ad76..c92841a9059c 100644 --- a/testing/webdriver/src/capabilities.rs +++ b/testing/webdriver/src/capabilities.rs @@ -163,7 +163,7 @@ impl SpecNewSessionParameters { fn validate_page_load_strategy(value: &Value) -> WebDriverResult<()> { match value { - &Value::String(ref x) => match &**x { + Value::String(x) => match &**x { "normal" | "eager" | "none" => {} x => { return Err(WebDriverError::new( diff --git a/testing/webdriver/src/command.rs b/testing/webdriver/src/command.rs index 0976acb42136..bd4f6d712a87 100644 --- a/testing/webdriver/src/command.rs +++ b/testing/webdriver/src/command.rs @@ -471,8 +471,8 @@ impl CapabilitiesMatching for NewSessionParameters { browser_capabilities: &mut T, ) -> WebDriverResult> { match self { - &NewSessionParameters::Spec(ref x) => x.match_browser(browser_capabilities), - &NewSessionParameters::Legacy(ref x) => x.match_browser(browser_capabilities), + NewSessionParameters::Spec(x) => x.match_browser(browser_capabilities), + NewSessionParameters::Legacy(x) => x.match_browser(browser_capabilities), } } } From ec4e9c209f6140b72d66b701024356053dd2cf50 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 14:59:04 +0100 Subject: [PATCH 11/80] Bug 1487993: webdriver: avoid explicitly calling iteration protocols; r=whimboo Instead of making explicit calls to iterator protocol methods such as x.iter() or x.into_iter(), we can loop over references to collections. This is considered better style. --- testing/webdriver/src/capabilities.rs | 10 +++++----- testing/webdriver/src/httpapi.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/testing/webdriver/src/capabilities.rs b/testing/webdriver/src/capabilities.rs index c92841a9059c..89ec422a2837 100644 --- a/testing/webdriver/src/capabilities.rs +++ b/testing/webdriver/src/capabilities.rs @@ -121,7 +121,7 @@ impl SpecNewSessionParameters { capabilities.remove(&key); } - for (key, value) in capabilities.iter() { + for (key, value) in &capabilities { match &**key { x @ "acceptInsecureCerts" | x @ "setWindowRect" => if !value.is_boolean() { return Err(WebDriverError::new( @@ -189,7 +189,7 @@ impl SpecNewSessionParameters { "proxy is not an object" ); - for (key, value) in obj.iter() { + for (key, value) in obj { match &**key { "proxyType" => match value.as_str() { Some("pac") | Some("direct") | Some("autodetect") | Some("system") @@ -326,7 +326,7 @@ impl SpecNewSessionParameters { "timeouts capability is not an object" ); - for (key, value) in obj.iter() { + for (key, value) in obj { match &**key { x @ "script" | x @ "pageLoad" | x @ "implicit" => { let timeout = try_opt!( @@ -412,7 +412,7 @@ impl CapabilitiesMatching for SpecNewSessionParameters { )); } let mut merged = self.alwaysMatch.clone(); - for (key, value) in first_match_entry.clone().into_iter() { + for (key, value) in first_match_entry.clone() { merged.insert(key, value); } Ok(merged) @@ -425,7 +425,7 @@ impl CapabilitiesMatching for SpecNewSessionParameters { .filter_map(|merged| { browser_capabilities.init(merged); - for (key, value) in merged.iter() { + for (key, value) in merged { match &**key { "browserName" => { let browserValue = browser_capabilities diff --git a/testing/webdriver/src/httpapi.rs b/testing/webdriver/src/httpapi.rs index 1581b4b62757..6d2be05c3d91 100644 --- a/testing/webdriver/src/httpapi.rs +++ b/testing/webdriver/src/httpapi.rs @@ -359,10 +359,10 @@ impl WebDriverHttpApi { pub fn new(extension_routes: &[(Method, &str, U)]) -> WebDriverHttpApi { let mut rv = WebDriverHttpApi:: { routes: vec![] }; debug!("Creating routes"); - for &(ref method, ref url, ref match_type) in standard_routes::().iter() { + for &(ref method, ref url, ref match_type) in &standard_routes::() { rv.add(method.clone(), *url, (*match_type).clone()); } - for &(ref method, ref url, ref extension_route) in extension_routes.iter() { + for &(ref method, ref url, ref extension_route) in extension_routes { rv.add( method.clone(), *url, @@ -384,7 +384,7 @@ impl WebDriverHttpApi { body: &str, ) -> WebDriverResult> { let mut error = ErrorStatus::UnknownPath; - for &(ref match_method, ref matcher) in self.routes.iter() { + for &(ref match_method, ref matcher) in &self.routes { if method == *match_method { let (method_match, captures) = matcher.get_match(method, path); if captures.is_some() { From ee01f5fc4186aec1987189097f212deba1b8c8dc Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Mon, 3 Sep 2018 11:50:11 +0100 Subject: [PATCH 12/80] Bug 1487986: webdriver: prefer x.is_empty() over x.len() == 0; r=whimboo --- testing/webdriver/src/capabilities.rs | 6 +++--- testing/webdriver/src/server.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/webdriver/src/capabilities.rs b/testing/webdriver/src/capabilities.rs index 89ec422a2837..269e5281ae2c 100644 --- a/testing/webdriver/src/capabilities.rs +++ b/testing/webdriver/src/capabilities.rs @@ -393,10 +393,10 @@ impl CapabilitiesMatching for SpecNewSessionParameters { browser_capabilities: &mut T, ) -> WebDriverResult> { let default = vec![Map::new()]; - let capabilities_list = if self.firstMatch.len() > 0 { - &self.firstMatch - } else { + let capabilities_list = if self.firstMatch.is_empty() { &default + } else { + &self.firstMatch }; let merged_capabilities = capabilities_list diff --git a/testing/webdriver/src/server.rs b/testing/webdriver/src/server.rs index 57d643311c06..24a44ba97d4a 100644 --- a/testing/webdriver/src/server.rs +++ b/testing/webdriver/src/server.rs @@ -77,7 +77,7 @@ impl, U: WebDriverExtensionRoute> Dispatcher { self.session = Some(Session::new(new_session.session_id.clone())); } Ok(WebDriverResponse::CloseWindow(CloseWindowResponse(ref handles))) => { - if handles.len() == 0 { + if handles.is_empty() { debug!("Last window was closed, deleting session"); self.delete_session(); } From 77c3ee5c113e437c160d3ab28ee31bd410293c5f Mon Sep 17 00:00:00 2001 From: Henrik Skupin Date: Tue, 4 Sep 2018 09:46:35 +0200 Subject: [PATCH 13/80] Bug 1488347 - [wdspec] Remove no longer needed manifest files. r=ato The manifest files can be removed because test names are invalid, or tests are passing meanwhile. --HG-- extra : rebase_source : 7f1f38bdaab85ccad222317b1162112ac19bb3ab --- .../tests/element_clear/clear.py.ini | 49 ------------------- .../tests/get_window_rect/user_prompts.py.ini | 3 -- .../tests/send_alert_text/send.py.ini | 13 ----- .../tests/set_window_rect/set.py.ini | 5 -- 4 files changed, 70 deletions(-) delete mode 100644 testing/web-platform/meta/webdriver/tests/element_clear/clear.py.ini delete mode 100644 testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini delete mode 100644 testing/web-platform/meta/webdriver/tests/send_alert_text/send.py.ini delete mode 100644 testing/web-platform/meta/webdriver/tests/set_window_rect/set.py.ini diff --git a/testing/web-platform/meta/webdriver/tests/element_clear/clear.py.ini b/testing/web-platform/meta/webdriver/tests/element_clear/clear.py.ini deleted file mode 100644 index eb65d33f793a..000000000000 --- a/testing/web-platform/meta/webdriver/tests/element_clear/clear.py.ini +++ /dev/null @@ -1,49 +0,0 @@ -[clear.py] - [test_clear_content_editable_resettable_element[element0\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element1\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element2\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element3\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element4\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element5\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element6\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element7\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element8\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element9\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element10\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element11\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element12\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element13\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element14\]] - expected: FAIL - - [test_clear_content_editable_resettable_element[element15\]] - expected: FAIL - diff --git a/testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini b/testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini deleted file mode 100644 index 363c4e9d7f27..000000000000 --- a/testing/web-platform/meta/webdriver/tests/get_window_rect/user_prompts.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[user_prompts.py] - disabled: - if not debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): wpt-sync Bug 1446953 diff --git a/testing/web-platform/meta/webdriver/tests/send_alert_text/send.py.ini b/testing/web-platform/meta/webdriver/tests/send_alert_text/send.py.ini deleted file mode 100644 index 4c1624cedb59..000000000000 --- a/testing/web-platform/meta/webdriver/tests/send_alert_text/send.py.ini +++ /dev/null @@ -1,13 +0,0 @@ -[send.py] - [test_send_alert_text] - expected: FAIL - - [test_confirm_element_not_interactable] - expected: FAIL - - [test_alert_element_not_interactable] - expected: FAIL - - [test_send_alert_text_with_whitespace] - expected: FAIL - diff --git a/testing/web-platform/meta/webdriver/tests/set_window_rect/set.py.ini b/testing/web-platform/meta/webdriver/tests/set_window_rect/set.py.ini deleted file mode 100644 index 2ab097627b56..000000000000 --- a/testing/web-platform/meta/webdriver/tests/set_window_rect/set.py.ini +++ /dev/null @@ -1,5 +0,0 @@ -[set.py] - [test_restore_from_maximized] - disabled: - if debug and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): wpt-sync Bug 1444624 - From 6d73891d22c95d0a393801e9052f9020a4d18a53 Mon Sep 17 00:00:00 2001 From: Henrik Skupin Date: Tue, 4 Sep 2018 09:48:48 +0200 Subject: [PATCH 14/80] Bug 1488347 - [wdspec] Re-enable tests formerly disabled for webrender. r=ato --HG-- extra : rebase_source : 742d9bf193fea32e03a8ff96bc31bb105230e03c --- .../meta/webdriver/tests/actions/mouse_dblclick.py.ini | 3 --- .../webdriver/tests/get_element_property/user_prompts.py.ini | 3 --- .../webdriver/tests/get_element_tag_name/user_prompts.py.ini | 3 --- .../meta/webdriver/tests/get_title/user_prompts.py.ini | 3 --- 4 files changed, 12 deletions(-) delete mode 100644 testing/web-platform/meta/webdriver/tests/actions/mouse_dblclick.py.ini delete mode 100644 testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini delete mode 100644 testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini delete mode 100644 testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini diff --git a/testing/web-platform/meta/webdriver/tests/actions/mouse_dblclick.py.ini b/testing/web-platform/meta/webdriver/tests/actions/mouse_dblclick.py.ini deleted file mode 100644 index 5b619995210b..000000000000 --- a/testing/web-platform/meta/webdriver/tests/actions/mouse_dblclick.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mouse_dblclick.py] - disabled: - if webrender: bug 1425588 diff --git a/testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini b/testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini deleted file mode 100644 index 550703cd7311..000000000000 --- a/testing/web-platform/meta/webdriver/tests/get_element_property/user_prompts.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[user_prompts.py] - disabled: - if webrender: bug 1425588 diff --git a/testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini b/testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini deleted file mode 100644 index 550703cd7311..000000000000 --- a/testing/web-platform/meta/webdriver/tests/get_element_tag_name/user_prompts.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[user_prompts.py] - disabled: - if webrender: bug 1425588 diff --git a/testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini b/testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini deleted file mode 100644 index 550703cd7311..000000000000 --- a/testing/web-platform/meta/webdriver/tests/get_title/user_prompts.py.ini +++ /dev/null @@ -1,3 +0,0 @@ -[user_prompts.py] - disabled: - if webrender: bug 1425588 From 7b7c50ebb6090a1bc654b36901768577b5ee51e8 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 17:15:51 +0100 Subject: [PATCH 15/80] Bug 1488007: mozversion: lint; r=jgraham Address clippy lint warnings in mozversion. --- testing/mozbase/rust/mozversion/src/lib.rs | 99 +++++++++++----------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/testing/mozbase/rust/mozversion/src/lib.rs b/testing/mozbase/rust/mozversion/src/lib.rs index 07fab5e37bc1..c099f3d2875a 100644 --- a/testing/mozbase/rust/mozversion/src/lib.rs +++ b/testing/mozbase/rust/mozversion/src/lib.rs @@ -89,43 +89,6 @@ pub struct Version { } impl Version { - pub fn from_str(version_string: &str) -> Result { - let mut version: Version = Default::default(); - let version_re = Regex::new(r"^(?P\d+)\.(?P\d+)(?:\.(?P\d+))?(?:(?P[a-z]+)(?P\d*))?$").unwrap(); - if let Some(captures) = version_re.captures(version_string) { - match captures.name("major") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - Some(x) => version.major = x, - None => return Err(Error::VersionError("No major version number found".into())) - } - match captures.name("minor") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - Some(x) => version.minor = x, - None => return Err(Error::VersionError("No minor version number found".into())) - } - match captures.name("patch") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - Some(x) => version.patch = x, - None => {} - } - if let Some(pre_0) = captures.name("pre0").map(|x| x.as_str().to_string()) { - if captures.name("pre1").is_some() { - if let Some(pre_1) = captures.name("pre1") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - version.pre = Some((pre_0, pre_1)) - } else { - return Err(Error::VersionError("Failed to convert prelease number to u64".into())); - } - } else { - return Err(Error::VersionError("Failed to convert prelease number to u64".into())); - } - } - } else { - return Err(Error::VersionError("Failed to parse input as version string".into())) - } - Ok(version) - } - fn to_semver(&self) -> semver::Version { // The way the semver crate handles prereleases isn't what we want here // This should be fixed in the long term by implementing our own comparison @@ -146,6 +109,45 @@ impl Version { } } +impl FromStr for Version { + type Err = Error; + + fn from_str(version_string: &str) -> Result { + let mut version: Version = Default::default(); + let version_re = Regex::new(r"^(?P\d+)\.(?P\d+)(?:\.(?P\d+))?(?:(?P[a-z]+)(?P\d*))?$").unwrap(); + if let Some(captures) = version_re.captures(version_string) { + match captures.name("major") + .and_then(|x| u64::from_str(x.as_str()).ok()) { + Some(x) => version.major = x, + None => return Err(Error::VersionError("No major version number found".into())) + } + match captures.name("minor") + .and_then(|x| u64::from_str(x.as_str()).ok()) { + Some(x) => version.minor = x, + None => return Err(Error::VersionError("No minor version number found".into())) + } + if let Some(x) = captures.name("patch") + .and_then(|x| u64::from_str(x.as_str()).ok()) { version.patch = x } + if let Some(pre_0) = captures.name("pre0").map(|x| x.as_str().to_string()) { + if captures.name("pre1").is_some() { + if let Some(pre_1) = captures.name("pre1") + .and_then(|x| u64::from_str(x.as_str()).ok()) { + version.pre = Some((pre_0, pre_1)) + } else { + return Err(Error::VersionError("Failed to convert prelease number to u64".into())); + } + } else { + return Err(Error::VersionError("Failed to convert prelease number to u64".into())); + } + } + } else { + return Err(Error::VersionError("Failed to parse input as version string".into())) + } + Ok(version) + } +} + + impl Display for Version { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.patch { @@ -212,16 +214,16 @@ pub enum Error { impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Error::VersionError(ref x) => { + match *self { + Error::VersionError(ref x) => { try!("VersionError: ".fmt(f)); x.fmt(f) }, - &Error::MetadataError(ref x) => { + Error::MetadataError(ref x) => { try!("MetadataError: ".fmt(f)); x.fmt(f) }, - &Error::SemVerError(ref e) => { + Error::SemVerError(ref e) => { try!("SemVerError: ".fmt(f)); e.fmt(f) } @@ -237,17 +239,17 @@ impl From for Error { impl error::Error for Error { fn description(&self) -> &str { - match self { - &Error::VersionError(ref x) => &*x, - &Error::MetadataError(ref x) => &*x, - &Error::SemVerError(ref e) => e.description(), + match *self { + Error::VersionError(ref x) => &*x, + Error::MetadataError(ref x) => &*x, + Error::SemVerError(ref e) => e.description(), } } fn cause(&self) -> Option<&error::Error> { - match self { - &Error::SemVerError(ref e) => Some(e), - _ => None, + match *self { + Error::SemVerError(ref e) => Some(e), + Error::VersionError(_) | Error::MetadataError(_) => None, } } } @@ -279,6 +281,7 @@ mod platform { #[cfg(test)] mod test { + use std::str::FromStr; use super::{Version}; fn parse_version(input: &str) -> String { From 397e3d27d51cd85856ec9e206575bfa75dc65f10 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 17:16:21 +0100 Subject: [PATCH 16/80] Bug 1488007: mozversion: format; r=jgraham No functional changes, except applying rustfmt. --- testing/mozbase/rust/mozversion/src/lib.rs | 103 +++++++++++++-------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/testing/mozbase/rust/mozversion/src/lib.rs b/testing/mozbase/rust/mozversion/src/lib.rs index c099f3d2875a..42d67e94d19d 100644 --- a/testing/mozbase/rust/mozversion/src/lib.rs +++ b/testing/mozbase/rust/mozversion/src/lib.rs @@ -3,8 +3,8 @@ extern crate regex; extern crate semver; use ini::Ini; -use regex::Regex; use platform::ini_path; +use regex::Regex; use std::default::Default; use std::error; use std::fmt::{self, Display, Formatter}; @@ -92,8 +92,8 @@ impl Version { fn to_semver(&self) -> semver::Version { // The way the semver crate handles prereleases isn't what we want here // This should be fixed in the long term by implementing our own comparison - // operators, but for now just act as if prerelease metadata was missing, otherwise - // it is almost impossible to use this with nightly + // operators, but for now just act as if prerelease metadata was missing, + // otherwise it is almost impossible to use this with nightly semver::Version { major: self.major, minor: self.minor, @@ -104,7 +104,7 @@ impl Version { } pub fn matches(&self, version_req: &str) -> Result { - let req = try!(semver::VersionReq::parse(version_req)); + let req = semver::VersionReq::parse(version_req)?; Ok(req.matches(&self.to_semver())) } } @@ -116,46 +116,61 @@ impl FromStr for Version { let mut version: Version = Default::default(); let version_re = Regex::new(r"^(?P\d+)\.(?P\d+)(?:\.(?P\d+))?(?:(?P[a-z]+)(?P\d*))?$").unwrap(); if let Some(captures) = version_re.captures(version_string) { - match captures.name("major") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - Some(x) => version.major = x, - None => return Err(Error::VersionError("No major version number found".into())) - } - match captures.name("minor") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - Some(x) => version.minor = x, - None => return Err(Error::VersionError("No minor version number found".into())) - } - if let Some(x) = captures.name("patch") - .and_then(|x| u64::from_str(x.as_str()).ok()) { version.patch = x } + match captures + .name("major") + .and_then(|x| u64::from_str(x.as_str()).ok()) + { + Some(x) => version.major = x, + None => return Err(Error::VersionError("No major version number found".into())), + } + match captures + .name("minor") + .and_then(|x| u64::from_str(x.as_str()).ok()) + { + Some(x) => version.minor = x, + None => return Err(Error::VersionError("No minor version number found".into())), + } + if let Some(x) = captures + .name("patch") + .and_then(|x| u64::from_str(x.as_str()).ok()) + { + version.patch = x + } if let Some(pre_0) = captures.name("pre0").map(|x| x.as_str().to_string()) { if captures.name("pre1").is_some() { - if let Some(pre_1) = captures.name("pre1") - .and_then(|x| u64::from_str(x.as_str()).ok()) { - version.pre = Some((pre_0, pre_1)) - } else { - return Err(Error::VersionError("Failed to convert prelease number to u64".into())); - } + if let Some(pre_1) = captures + .name("pre1") + .and_then(|x| u64::from_str(x.as_str()).ok()) + { + version.pre = Some((pre_0, pre_1)) + } else { + return Err(Error::VersionError( + "Failed to convert prelease number to u64".into(), + )); + } } else { - return Err(Error::VersionError("Failed to convert prelease number to u64".into())); + return Err(Error::VersionError( + "Failed to convert prelease number to u64".into(), + )); } } } else { - return Err(Error::VersionError("Failed to parse input as version string".into())) + return Err(Error::VersionError( + "Failed to parse input as version string".into(), + )); } Ok(version) } } - impl Display for Version { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.patch { - 0 => try!(write!(f, "{}.{}", self.major, self.minor)), - _ => try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)) + 0 => write!(f, "{}.{}", self.major, self.minor)?, + _ => write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?, } if let Some(ref pre) = self.pre { - try!(write!(f, "{}{}", pre.0, pre.1)); + write!(f, "{}{}", pre.0, pre.1)?; }; Ok(()) } @@ -166,7 +181,7 @@ impl Display for Version { /// Given the path to a Firefox binary, read the associated application.ini /// and platform.ini files to extract information about the version of Firefox /// at that path. -pub fn firefox_version(binary: &Path) -> Result { +pub fn firefox_version(binary: &Path) -> Result { let mut version = AppVersion::new(); let mut updated = false; @@ -194,10 +209,12 @@ pub fn firefox_version(binary: &Path) -> Result { } if !updated { - return Err(Error::MetadataError("Neither platform.ini nor application.ini found".into())) + return Err(Error::MetadataError( + "Neither platform.ini nor application.ini found".into(), + )); } } else { - return Err(Error::MetadataError("Invalid binary path".into())) + return Err(Error::MetadataError("Invalid binary path".into())); } Ok(version) } @@ -209,22 +226,22 @@ pub enum Error { /// Error reading application metadata MetadataError(String), /// Error processing a string as a semver comparator - SemVerError(semver::ReqParseError) + SemVerError(semver::ReqParseError), } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::VersionError(ref x) => { - try!("VersionError: ".fmt(f)); + "VersionError: ".fmt(f)?; x.fmt(f) - }, + } Error::MetadataError(ref x) => { - try!("MetadataError: ".fmt(f)); + "MetadataError: ".fmt(f)?; x.fmt(f) - }, + } Error::SemVerError(ref e) => { - try!("SemVerError: ".fmt(f)); + "SemVerError: ".fmt(f)?; e.fmt(f) } } @@ -259,7 +276,9 @@ mod platform { use std::path::{Path, PathBuf}; pub fn ini_path(binary: &Path) -> Option { - binary.canonicalize().ok() + binary + .canonicalize() + .ok() .as_ref() .and_then(|dir| dir.parent()) .and_then(|dir| dir.parent()) @@ -272,7 +291,9 @@ mod platform { use std::path::{Path, PathBuf}; pub fn ini_path(binary: &Path) -> Option { - binary.canonicalize().ok() + binary + .canonicalize() + .ok() .as_ref() .and_then(|dir| dir.parent()) .map(|dir| dir.to_path_buf()) @@ -281,8 +302,8 @@ mod platform { #[cfg(test)] mod test { + use super::Version; use std::str::FromStr; - use super::{Version}; fn parse_version(input: &str) -> String { Version::from_str(input).unwrap().to_string() @@ -316,7 +337,7 @@ mod test { assert!(compare("50.1.0", ">=50,<51")); assert!(compare("50.0a1", ">49.0")); assert!(compare("50.0a2", "=50")); - //This is the weird one + // This is the weird one assert!(!compare("50.0a2", ">50.0")); } } From 36a56411ed233bedff4b852f8262c4a9996b660c Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Tue, 4 Sep 2018 16:26:31 +0300 Subject: [PATCH 17/80] Backed out changeset 015d294ad0ea (bug 1488395) for spidermokey failures --- js/src/wasm/WasmTextToBinary.cpp | 2 -- js/src/wasm/WasmValidate.h | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/js/src/wasm/WasmTextToBinary.cpp b/js/src/wasm/WasmTextToBinary.cpp index fa215606a817..6f78c29758bd 100644 --- a/js/src/wasm/WasmTextToBinary.cpp +++ b/js/src/wasm/WasmTextToBinary.cpp @@ -1176,10 +1176,8 @@ WasmTokenStream::next() break; case 'g': -#ifdef ENABLE_WASM_GC if (consume(u"gc_feature_opt_in")) return WasmToken(WasmToken::GcFeatureOptIn, begin, cur_); -#endif if (consume(u"get_global")) return WasmToken(WasmToken::GetGlobal, begin, cur_); if (consume(u"get_local")) diff --git a/js/src/wasm/WasmValidate.h b/js/src/wasm/WasmValidate.h index 678363c4bdd9..dbab1135d7d5 100644 --- a/js/src/wasm/WasmValidate.h +++ b/js/src/wasm/WasmValidate.h @@ -139,13 +139,13 @@ struct ModuleEnvironment size_t numFuncDefs() const { return funcTypes.length() - funcImportGlobalDataOffsets.length(); } - HasGcTypes gcTypesEnabled() const { #ifdef ENABLE_WASM_GC + HasGcTypes gcTypesEnabled() const { if (gcTypesConfigured == HasGcTypes::True) return gcFeatureOptIn; -#endif return HasGcTypes::False; } +#endif bool usesMemory() const { return memoryUsage != MemoryUsage::None; } From 6064b9610a151c22b906f7a0fbfd324044fce3dc Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:32:21 +0100 Subject: [PATCH 18/80] Bug 1488006: mozprofile: format code; r=jgraham No functional changes, apart from running all the code through rustfmt prior to fixing clippy lint warnings. --- testing/mozbase/rust/mozprofile/src/lib.rs | 180 +++-- .../rust/mozprofile/src/preferences.rs | 5 +- .../mozbase/rust/mozprofile/src/prefreader.rs | 694 ++++++++++-------- .../mozbase/rust/mozprofile/src/profile.rs | 30 +- 4 files changed, 477 insertions(+), 432 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/lib.rs b/testing/mozbase/rust/mozprofile/src/lib.rs index ef7a52274b0f..cedb54809248 100644 --- a/testing/mozbase/rust/mozprofile/src/lib.rs +++ b/testing/mozbase/rust/mozprofile/src/lib.rs @@ -1,17 +1,16 @@ extern crate tempdir; -pub mod profile; pub mod preferences; pub mod prefreader; - +pub mod profile; #[cfg(test)] mod test { -// use std::fs::File; -// use profile::Profile; - use prefreader::{parse, tokenize, serialize}; - use prefreader::{PrefToken, Position}; + // use std::fs::File; + // use profile::Profile; use preferences::Pref; + use prefreader::{parse, serialize, tokenize}; + use prefreader::{Position, PrefToken}; use std::collections::BTreeMap; use std::error::Error; use std::io::Cursor; @@ -19,55 +18,62 @@ mod test { #[test] fn tokenize_simple() { - let prefs = " user_pref ( 'example.pref.string', 'value' ) ;\n pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false);"; + let prefs = " user_pref ( 'example.pref.string', 'value' ) ;\n \ + pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false);"; let p = Position::new(); - let expected = vec![PrefToken::UserPrefFunction(p), - PrefToken::Paren('(', p), - PrefToken::String("example.pref.string".into(), p), - PrefToken::Comma(p), - PrefToken::String("value".into(), p), - PrefToken::Paren(')', p), - PrefToken::Semicolon(p), - PrefToken::PrefFunction(p), - PrefToken::Paren('(', p), - PrefToken::String("example.pref.int".into(), p), - PrefToken::Comma(p), - PrefToken::Int(-123, p), - PrefToken::Paren(')', p), - PrefToken::Semicolon(p), - PrefToken::StickyPrefFunction(p), - PrefToken::Paren('(', p), - PrefToken::String("example.pref.bool".into(), p), - PrefToken::Comma(p), - PrefToken::Bool(false, p), - PrefToken::Paren(')', p), - PrefToken::Semicolon(p)]; + let expected = vec![ + PrefToken::UserPrefFunction(p), + PrefToken::Paren('(', p), + PrefToken::String("example.pref.string".into(), p), + PrefToken::Comma(p), + PrefToken::String("value".into(), p), + PrefToken::Paren(')', p), + PrefToken::Semicolon(p), + PrefToken::PrefFunction(p), + PrefToken::Paren('(', p), + PrefToken::String("example.pref.int".into(), p), + PrefToken::Comma(p), + PrefToken::Int(-123, p), + PrefToken::Paren(')', p), + PrefToken::Semicolon(p), + PrefToken::StickyPrefFunction(p), + PrefToken::Paren('(', p), + PrefToken::String("example.pref.bool".into(), p), + PrefToken::Comma(p), + PrefToken::Bool(false, p), + PrefToken::Paren(')', p), + PrefToken::Semicolon(p), + ]; tokenize_test(prefs, &expected); } #[test] fn tokenize_comments() { - let prefs = "# bash style comment\n /*block comment*/ user_pref/*block comment*/(/*block comment*/ 'example.pref.string' /*block comment*/,/*block comment*/ 'value'/*block comment*/ )// line comment"; + let prefs = "# bash style comment\n /*block comment*/ user_pref/*block comment*/(/*block \ + comment*/ 'example.pref.string' /*block comment*/,/*block comment*/ \ + 'value'/*block comment*/ )// line comment"; let p = Position::new(); - let expected = vec![PrefToken::CommentBashLine(" bash style comment".into(), p), - PrefToken::CommentBlock("block comment".into(), p), - PrefToken::UserPrefFunction(p), - PrefToken::CommentBlock("block comment".into(), p), - PrefToken::Paren('(', p), - PrefToken::CommentBlock("block comment".into(), p), - PrefToken::String("example.pref.string".into(), p), - PrefToken::CommentBlock("block comment".into(), p), - PrefToken::Comma(p), - PrefToken::CommentBlock("block comment".into(), p), - PrefToken::String("value".into(), p), - PrefToken::CommentBlock("block comment".into(), p), - PrefToken::Paren(')', p), - PrefToken::CommentLine(" line comment".into(), p)]; + let expected = vec![ + PrefToken::CommentBashLine(" bash style comment".into(), p), + PrefToken::CommentBlock("block comment".into(), p), + PrefToken::UserPrefFunction(p), + PrefToken::CommentBlock("block comment".into(), p), + PrefToken::Paren('(', p), + PrefToken::CommentBlock("block comment".into(), p), + PrefToken::String("example.pref.string".into(), p), + PrefToken::CommentBlock("block comment".into(), p), + PrefToken::Comma(p), + PrefToken::CommentBlock("block comment".into(), p), + PrefToken::String("value".into(), p), + PrefToken::CommentBlock("block comment".into(), p), + PrefToken::Paren(')', p), + PrefToken::CommentLine(" line comment".into(), p), + ]; tokenize_test(prefs, &expected); } @@ -78,12 +84,14 @@ mod test { let p = Position::new(); - let expected = vec![PrefToken::UserPrefFunction(p), - PrefToken::Paren('(', p), - PrefToken::String("example pref".into(), p), - PrefToken::Comma(p), - PrefToken::String(" ☃𐂖\"'\n\r\\\\w".into(), p), - PrefToken::Paren(')', p)]; + let expected = vec![ + PrefToken::UserPrefFunction(p), + PrefToken::Paren('(', p), + PrefToken::String("example pref".into(), p), + PrefToken::Comma(p), + PrefToken::String(" ☃𐂖\"'\n\r\\\\w".into(), p), + PrefToken::Paren(')', p), + ]; tokenize_test(prefs, &expected); } @@ -93,49 +101,31 @@ mod test { for (e, a) in expected.iter().zip(tokenize(prefs.as_bytes())) { let success = match (e, &a) { - (&PrefToken::PrefFunction(_), - &PrefToken::PrefFunction(_)) => true, - (&PrefToken::UserPrefFunction(_), - &PrefToken::UserPrefFunction(_)) => true, - (&PrefToken::StickyPrefFunction(_), - &PrefToken::StickyPrefFunction(_)) => true, - (&PrefToken::CommentBlock(ref data_e, _), - &PrefToken::CommentBlock(ref data_a, _)) => { + (&PrefToken::PrefFunction(_), &PrefToken::PrefFunction(_)) => true, + (&PrefToken::UserPrefFunction(_), &PrefToken::UserPrefFunction(_)) => true, + (&PrefToken::StickyPrefFunction(_), &PrefToken::StickyPrefFunction(_)) => true, + ( + &PrefToken::CommentBlock(ref data_e, _), + &PrefToken::CommentBlock(ref data_a, _), + ) => data_e == data_a, + ( + &PrefToken::CommentLine(ref data_e, _), + &PrefToken::CommentLine(ref data_a, _), + ) => data_e == data_a, + ( + &PrefToken::CommentBashLine(ref data_e, _), + &PrefToken::CommentBashLine(ref data_a, _), + ) => data_e == data_a, + (&PrefToken::Paren(data_e, _), &PrefToken::Paren(data_a, _)) => data_e == data_a, + (&PrefToken::Semicolon(_), &PrefToken::Semicolon(_)) => true, + (&PrefToken::Comma(_), &PrefToken::Comma(_)) => true, + (&PrefToken::String(ref data_e, _), &PrefToken::String(ref data_a, _)) => { data_e == data_a - }, - (&PrefToken::CommentLine(ref data_e, _), - &PrefToken::CommentLine(ref data_a, _)) => { - data_e == data_a - }, - (&PrefToken::CommentBashLine(ref data_e, _), - &PrefToken::CommentBashLine(ref data_a, _)) => { - data_e == data_a - }, - (&PrefToken::Paren(data_e, _), - &PrefToken::Paren(data_a, _)) => { - data_e == data_a - }, - (&PrefToken::Semicolon(_), - &PrefToken::Semicolon(_)) => true, - (&PrefToken::Comma(_), - &PrefToken::Comma(_)) => true, - (&PrefToken::String(ref data_e, _), - &PrefToken::String(ref data_a, _)) => { - data_e == data_a - }, - (&PrefToken::Int(data_e, _), - &PrefToken::Int(data_a, _)) => { - data_e == data_a - }, - (&PrefToken::Bool(data_e, _), - &PrefToken::Bool(data_a, _)) => { - data_e == data_a - }, - (&PrefToken::Error(data_e, _), - &PrefToken::Error(data_a, _)) => { - data_e == data_a - }, - (_, _) => false + } + (&PrefToken::Int(data_e, _), &PrefToken::Int(data_a, _)) => data_e == data_a, + (&PrefToken::Bool(data_e, _), &PrefToken::Bool(data_a, _)) => data_e == data_a, + (&PrefToken::Error(data_e, _), &PrefToken::Error(data_a, _)) => data_e == data_a, + (_, _) => false, }; if !success { println!("Expected {:?}, got {:?}", e, a); @@ -146,7 +136,8 @@ mod test { #[test] fn parse_simple() { - let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; + let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n \ + pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; let mut expected: BTreeMap = BTreeMap::new(); expected.insert("example.pref.string".into(), Pref::new("value")); @@ -177,11 +168,12 @@ mod test { assert!(false) } } - } + } #[test] fn serialize_simple() { - let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; + let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n \ + pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; let expected = "sticky_pref(\"example.pref.bool\", false); user_pref(\"example.pref.int\", -123); user_pref(\"example.pref.string\", \"value\");\n"; diff --git a/testing/mozbase/rust/mozprofile/src/preferences.rs b/testing/mozbase/rust/mozprofile/src/preferences.rs index 619b708fee11..ee9c24510ba5 100644 --- a/testing/mozbase/rust/mozprofile/src/preferences.rs +++ b/testing/mozbase/rust/mozprofile/src/preferences.rs @@ -112,7 +112,10 @@ mod test { #[test] fn test_string() { assert_eq!(PrefValue::from("foo"), PrefValue::String("foo".to_string())); - assert_eq!(PrefValue::from("foo".to_string()), PrefValue::String("foo".to_string())); + assert_eq!( + PrefValue::from("foo".to_string()), + PrefValue::String("foo".to_string()) + ); } #[test] diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index ba2507cdbc50..5c6dffbe9d63 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -6,29 +6,34 @@ use std::error::Error; use std::fmt; use std::io::{self, Write}; use std::iter::Iterator; -use std::str; use std::mem; use std::ops::Deref; +use std::str; impl PrefReaderError { - fn new(message: &'static str, position: Position, parent: Option>) -> PrefReaderError { + fn new( + message: &'static str, + position: Position, + parent: Option>, + ) -> PrefReaderError { PrefReaderError { message: message, position: position, - parent: parent + parent: parent, } } } - impl fmt::Display for PrefReaderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} at line {}, column {}", - self.message, self.position.line, self.position.column) + write!( + f, + "{} at line {}, column {}", + self.message, self.position.line, self.position.column + ) } } - impl Error for PrefReaderError { fn description(&self) -> &str { self.message @@ -37,16 +42,14 @@ impl Error for PrefReaderError { fn cause(&self) -> Option<&Error> { match self.parent { None => None, - Some(ref cause) => Some(cause.deref()) + Some(ref cause) => Some(cause.deref()), } } } impl From for PrefReaderError { fn from(err: io::Error) -> PrefReaderError { - PrefReaderError::new("IOError", - Position::new(), - Some(err.into())) + PrefReaderError::new("IOError", Position::new(), Some(err.into())) } } @@ -72,15 +75,12 @@ enum TokenizerState { #[derive(Copy, Clone, Debug, PartialEq)] pub struct Position { line: u32, - column: u32 + column: u32, } impl Position { pub fn new() -> Position { - Position { - line: 1, - column: 0 - } + Position { line: 1, column: 0 } } } @@ -99,7 +99,7 @@ pub enum TokenType { String, Int, Bool, - Error + Error, } #[derive(Debug, PartialEq)] @@ -116,7 +116,7 @@ pub enum PrefToken<'a> { String(Cow<'a, str>, Position), Int(i64, Position), Bool(bool, Position), - Error(&'static str, Position) + Error(&'static str, Position), } impl<'a> PrefToken<'a> { @@ -134,7 +134,7 @@ impl<'a> PrefToken<'a> { PrefToken::String(_, position) => position, PrefToken::Int(_, position) => position, PrefToken::Bool(_, position) => position, - PrefToken::Error(_, position) => position + PrefToken::Error(_, position) => position, } } } @@ -143,7 +143,7 @@ impl<'a> PrefToken<'a> { pub struct PrefReaderError { message: &'static str, position: Position, - parent: Option> + parent: Option>, } struct TokenData<'a> { @@ -180,8 +180,11 @@ impl<'a> TokenData<'a> { let data = match str::from_utf8(&buf[self.start_pos..end_pos]) { Ok(x) => x, Err(_) => { - return Err(PrefReaderError::new("Could not convert string to utf8", - self.position, None)); + return Err(PrefReaderError::new( + "Could not convert string to utf8", + self.position, + None, + )); } }; if self.data != "" { @@ -235,31 +238,31 @@ impl<'a> PrefTokenizer<'a> { panic!("Expected a buffer of length one"); } PrefToken::Paren(buf.chars().next().unwrap(), position) - }, + } TokenType::Semicolon => PrefToken::Semicolon(position), TokenType::Comma => PrefToken::Comma(position), TokenType::String => PrefToken::String(buf, position), TokenType::Int => { - let value = i64::from_str_radix(buf.borrow(), 10) - .expect("Integer wasn't parsed as an i64"); + let value = + i64::from_str_radix(buf.borrow(), 10).expect("Integer wasn't parsed as an i64"); PrefToken::Int(value, position) - }, + } TokenType::Bool => { let value = match buf.borrow() { "true" => true, "false" => false, - x => panic!(format!("Boolean wasn't 'true' or 'false' (was {})", x)) + x => panic!(format!("Boolean wasn't 'true' or 'false' (was {})", x)), }; PrefToken::Bool(value, position) - }, - TokenType::Error => panic!("make_token can't construct errors") + } + TokenType::Error => panic!("make_token can't construct errors"), } } fn get_char(&mut self) -> Option { if self.pos >= self.data.len() - 1 { self.cur = None; - return None + return None; }; if self.cur.is_some() { self.pos += 1; @@ -300,7 +303,7 @@ impl<'a> PrefTokenizer<'a> { fn is_space(c: char) -> bool { match c { ' ' | '\t' | '\r' | '\n' => true, - _ => false + _ => false, } } @@ -309,7 +312,7 @@ impl<'a> PrefTokenizer<'a> { if PrefTokenizer::is_space(c) { self.get_char(); } else { - break + break; }; } self.cur @@ -317,9 +320,9 @@ impl<'a> PrefTokenizer<'a> { fn consume_escape(&mut self, token_data: &mut TokenData<'a>) -> Result<(), PrefReaderError> { let pos = self.pos; - let escaped = try!(self.read_escape()); + let escaped = self.read_escape()?; if let Some(escape_char) = escaped { - try!(token_data.add_slice_to_token(&self.data, pos)); + token_data.add_slice_to_token(&self.data, pos)?; token_data.push_char(&self, escape_char); }; Ok(()) @@ -327,20 +330,25 @@ impl<'a> PrefTokenizer<'a> { fn read_escape(&mut self) -> Result, PrefReaderError> { let escape_char = match self.get_char() { - Some('u') => try!(self.read_hex_escape(4, true)), - Some('x') => try!(self.read_hex_escape(2, true)), + Some('u') => self.read_hex_escape(4, true)?, + Some('x') => self.read_hex_escape(2, true)?, Some('\\') => '\\' as u32, Some('"') => '"' as u32, Some('\'') => '\'' as u32, Some('r') => '\r' as u32, Some('n') => '\n' as u32, Some(_) => return Ok(None), - None => return Err(PrefReaderError::new("EOF in character escape", - self.position, None)) + None => { + return Err(PrefReaderError::new( + "EOF in character escape", + self.position, + None, + )) + } }; - Ok(Some(try!(char::from_u32(escape_char) - .ok_or(PrefReaderError::new("Invalid codepoint decoded from escape", - self.position, None))))) + Ok(Some(char::from_u32(escape_char).ok_or( + PrefReaderError::new("Invalid codepoint decoded from escape", self.position, None), + )?)) } fn read_hex_escape(&mut self, hex_chars: isize, first: bool) -> Result { @@ -353,34 +361,51 @@ impl<'a> PrefTokenizer<'a> { '0'...'9' => value += x as u32 - '0' as u32, 'a'...'f' => value += x as u32 - 'a' as u32, 'A'...'F' => value += x as u32 - 'A' as u32, - _ => return Err(PrefReaderError::new( - "Unexpected character in escape", self.position, None)) + _ => { + return Err(PrefReaderError::new( + "Unexpected character in escape", + self.position, + None, + )) + } } - }, - None => return Err(PrefReaderError::new( - "Unexpected EOF in escape", self.position, None)) + } + None => { + return Err(PrefReaderError::new( + "Unexpected EOF in escape", + self.position, + None, + )) + } } } if first && value >= 0xD800 && value <= 0xDBFF { // First part of a surrogate pair if self.get_char() != Some('\\') || self.get_char() != Some('u') { - return Err(PrefReaderError::new("Lone high surrogate in surrogate pair", - self.position, None)) + return Err(PrefReaderError::new( + "Lone high surrogate in surrogate pair", + self.position, + None, + )); } self.unget_char(); let high_surrogate = value; - let low_surrogate = try!(self.read_hex_escape(4, false)); + let low_surrogate = self.read_hex_escape(4, false)?; let high_value = (high_surrogate - 0xD800) << 10; let low_value = low_surrogate - 0xDC00; value = high_value + low_value + 0x10000; } else if first && value >= 0xDC00 && value <= 0xDFFF { - return Err(PrefReaderError::new("Lone low surrogate", - self.position, - None)) + return Err(PrefReaderError::new( + "Lone low surrogate", + self.position, + None, + )); } else if !first && (value < 0xDC00 || value > 0xDFFF) { - return Err(PrefReaderError::new("Invalid low surrogate in surrogate pair", - self.position, - None)); + return Err(PrefReaderError::new( + "Invalid low surrogate in surrogate pair", + self.position, + None, + )); } Ok(value) } @@ -420,14 +445,14 @@ impl<'a> PrefTokenizer<'a> { loop { let mut c = match self.get_char() { Some(x) => x, - None => return Ok(None) + None => return Ok(None), }; self.state = match self.state { TokenizerState::Junk => { c = match self.skip_whitespace() { Some(x) => x, - None => return Ok(None) + None => return Ok(None), }; match c { '/' => TokenizerState::CommentStart, @@ -435,7 +460,7 @@ impl<'a> PrefTokenizer<'a> { token_data.start(&self, TokenType::CommentBashLine); token_data.start_pos = self.pos + 1; TokenizerState::CommentLine - }, + } _ => { self.unget_char(); let next = match self.next_state { @@ -444,56 +469,51 @@ impl<'a> PrefTokenizer<'a> { return Err(PrefReaderError::new( "In Junk state without a next state defined", self.position, - None)) + None, + )) } }; self.next_state = None; next } } - }, - TokenizerState::CommentStart => { - match c { - '*' => { - token_data.start(&self, TokenType::CommentBlock); - token_data.start_pos = self.pos + 1; - TokenizerState::CommentBlock - }, - '/' => { - token_data.start(&self, TokenType::CommentLine); - token_data.start_pos = self.pos + 1; - TokenizerState::CommentLine - }, - _ => { - return Err(PrefReaderError::new( - "Invalid character after /", self.position, None)) - } + } + TokenizerState::CommentStart => match c { + '*' => { + token_data.start(&self, TokenType::CommentBlock); + token_data.start_pos = self.pos + 1; + TokenizerState::CommentBlock + } + '/' => { + token_data.start(&self, TokenType::CommentLine); + token_data.start_pos = self.pos + 1; + TokenizerState::CommentLine + } + _ => { + return Err(PrefReaderError::new( + "Invalid character after /", + self.position, + None, + )) } - }, - TokenizerState::CommentLine => { - match c { - '\n' => { - try!(token_data.end(&self.data, self.pos)); + TokenizerState::CommentLine => match c { + '\n' => { + token_data.end(&self.data, self.pos)?; + TokenizerState::Junk + } + _ => TokenizerState::CommentLine, + }, + TokenizerState::CommentBlock => match c { + '*' => { + if self.get_char() == Some('/') { + token_data.end(&self.data, self.pos - 1)?; TokenizerState::Junk - }, - _ => { - TokenizerState::CommentLine + } else { + TokenizerState::CommentBlock } } - }, - TokenizerState::CommentBlock => { - match c { - '*' => { - if self.get_char() == Some('/') { - try!(token_data.end(&self.data, self.pos - 1)); - TokenizerState::Junk - } else { - TokenizerState::CommentBlock - } - }, - _ => TokenizerState::CommentBlock - } + _ => TokenizerState::CommentBlock, }, TokenizerState::FunctionName => { let position = self.position; @@ -503,7 +523,7 @@ impl<'a> PrefTokenizer<'a> { if self.get_match("user_pref", "(") { token_data.start(&self, TokenType::UserPrefFunction); } - }, + } 's' => { if self.get_match("sticky_pref", "(") { token_data.start(&self, TokenType::StickyPrefFunction); @@ -513,133 +533,136 @@ impl<'a> PrefTokenizer<'a> { if self.get_match("pref", "(") { token_data.start(&self, TokenType::PrefFunction); } - }, + } _ => {} }; if token_data.token_type == TokenType::None { // We didn't match anything return Err(PrefReaderError::new( - "Expected a pref function name", position, None)) + "Expected a pref function name", + position, + None, + )); } else { token_data.start_pos = start_pos; token_data.position = position; - try!(token_data.end(&self.data, self.pos + 1)); + token_data.end(&self.data, self.pos + 1)?; self.next_state = Some(TokenizerState::AfterFunctionName); TokenizerState::Junk } - }, - TokenizerState::AfterFunctionName => { - match c { - '(' => { - self.next_state = Some(TokenizerState::FunctionArgs); - token_data.start(&self, TokenType::Paren); - try!(token_data.end(&self.data, self.pos + 1)); - self.next_state = Some(TokenizerState::FunctionArgs); - TokenizerState::Junk - }, - _ => { - return Err(PrefReaderError::new( - "Expected an opening paren", self.position, None)) - } + } + TokenizerState::AfterFunctionName => match c { + '(' => { + self.next_state = Some(TokenizerState::FunctionArgs); + token_data.start(&self, TokenType::Paren); + token_data.end(&self.data, self.pos + 1)?; + self.next_state = Some(TokenizerState::FunctionArgs); + TokenizerState::Junk + } + _ => { + return Err(PrefReaderError::new( + "Expected an opening paren", + self.position, + None, + )) } }, - TokenizerState::FunctionArgs => { - match c { - ')' => { - token_data.start(&self, TokenType::Paren); - try!(token_data.end(&self.data, self.pos + 1)); - self.next_state = Some(TokenizerState::AfterFunction); - TokenizerState::Junk - }, - _ => { - self.unget_char(); - TokenizerState::FunctionArg - } + TokenizerState::FunctionArgs => match c { + ')' => { + token_data.start(&self, TokenType::Paren); + token_data.end(&self.data, self.pos + 1)?; + self.next_state = Some(TokenizerState::AfterFunction); + TokenizerState::Junk + } + _ => { + self.unget_char(); + TokenizerState::FunctionArg } }, - TokenizerState::FunctionArg => { - match c { - '"' => { - token_data.start(&self, TokenType::String); - token_data.start_pos = self.pos + 1; - TokenizerState::DoubleQuotedString - }, - '\'' => { - token_data.start(&self, TokenType::String); - token_data.start_pos = self.pos + 1; - TokenizerState::SingleQuotedString - }, - 't' | 'f' => { - self.unget_char(); - TokenizerState::Bool - }, - '0'...'9' | '-' |'+' => { - token_data.start(&self, TokenType::Int); - TokenizerState::Number - }, - _ => { - return Err(PrefReaderError::new( - "Invalid character at start of function argument", - self.position, None)) - } + TokenizerState::FunctionArg => match c { + '"' => { + token_data.start(&self, TokenType::String); + token_data.start_pos = self.pos + 1; + TokenizerState::DoubleQuotedString + } + '\'' => { + token_data.start(&self, TokenType::String); + token_data.start_pos = self.pos + 1; + TokenizerState::SingleQuotedString + } + 't' | 'f' => { + self.unget_char(); + TokenizerState::Bool + } + '0'...'9' | '-' | '+' => { + token_data.start(&self, TokenType::Int); + TokenizerState::Number + } + _ => { + return Err(PrefReaderError::new( + "Invalid character at start of function argument", + self.position, + None, + )) } }, - TokenizerState::DoubleQuotedString => { - match c { - '"' => { - try!(token_data.end(&self.data, self.pos)); - self.next_state = Some(TokenizerState::AfterFunctionArg); - TokenizerState::Junk - - }, - '\n' => { - return Err(PrefReaderError::new( - "EOL in double quoted string", self.position, None)) - }, - '\\' => { - try!(self.consume_escape(&mut token_data)); - TokenizerState::DoubleQuotedString - }, - _ => TokenizerState::DoubleQuotedString + TokenizerState::DoubleQuotedString => match c { + '"' => { + token_data.end(&self.data, self.pos)?; + self.next_state = Some(TokenizerState::AfterFunctionArg); + TokenizerState::Junk } - }, - TokenizerState::SingleQuotedString => { - match c { - '\'' => { - try!(token_data.end(&self.data, self.pos)); - self.next_state = Some(TokenizerState::AfterFunctionArg); - TokenizerState::Junk - - }, - '\n' => { - return Err(PrefReaderError::new( - "EOL in single quoted string", self.position, None)) - }, - '\\' => { - try!(self.consume_escape(&mut token_data)); - TokenizerState::SingleQuotedString - } - _ => TokenizerState::SingleQuotedString + '\n' => { + return Err(PrefReaderError::new( + "EOL in double quoted string", + self.position, + None, + )) } + '\\' => { + self.consume_escape(&mut token_data)?; + TokenizerState::DoubleQuotedString + } + _ => TokenizerState::DoubleQuotedString, }, - TokenizerState::Number => { - match c { - '0'...'9' => TokenizerState::Number, - ')' | ',' => { - try!(token_data.end(&self.data, self.pos)); - self.unget_char(); - self.next_state = Some(TokenizerState::AfterFunctionArg); - TokenizerState::Junk - }, - x if PrefTokenizer::is_space(x) => { - try!(token_data.end(&self.data, self.pos)); - self.next_state = Some(TokenizerState::AfterFunctionArg); - TokenizerState::Junk - }, - _ => { - return Err(PrefReaderError::new( - "Invalid character in number literal", self.position, None)) - } + TokenizerState::SingleQuotedString => match c { + '\'' => { + token_data.end(&self.data, self.pos)?; + self.next_state = Some(TokenizerState::AfterFunctionArg); + TokenizerState::Junk + } + '\n' => { + return Err(PrefReaderError::new( + "EOL in single quoted string", + self.position, + None, + )) + } + '\\' => { + self.consume_escape(&mut token_data)?; + TokenizerState::SingleQuotedString + } + _ => TokenizerState::SingleQuotedString, + }, + TokenizerState::Number => match c { + '0'...'9' => TokenizerState::Number, + ')' | ',' => { + token_data.end(&self.data, self.pos)?; + self.unget_char(); + self.next_state = Some(TokenizerState::AfterFunctionArg); + TokenizerState::Junk + } + x if PrefTokenizer::is_space(x) => { + token_data.end(&self.data, self.pos)?; + self.next_state = Some(TokenizerState::AfterFunctionArg); + TokenizerState::Junk + } + _ => { + return Err(PrefReaderError::new( + "Invalid character in number literal", + self.position, + None, + )) } }, TokenizerState::Bool => { @@ -650,7 +673,7 @@ impl<'a> PrefTokenizer<'a> { if self.get_match("true", ",)") { token_data.start(&self, TokenType::Bool) } - }, + } 'f' => { if self.get_match("false", ",)") { token_data.start(&self, TokenType::Bool) @@ -661,49 +684,54 @@ impl<'a> PrefTokenizer<'a> { if token_data.token_type == TokenType::None { return Err(PrefReaderError::new( "Unexpected characters in function argument", - position, None)); + position, + None, + )); } else { token_data.start_pos = start_pos; token_data.position = position; - try!(token_data.end(&self.data, self.pos + 1)); + token_data.end(&self.data, self.pos + 1)?; self.next_state = Some(TokenizerState::AfterFunctionArg); TokenizerState::Junk } - }, - TokenizerState::AfterFunctionArg => { - match c { - ',' => { - token_data.start(&self, TokenType::Comma); - try!(token_data.end(&self.data, self.pos + 1)); - self.next_state = Some(TokenizerState::FunctionArg); - TokenizerState::Junk - } - ')' => { - token_data.start(&self, TokenType::Paren); - try!(token_data.end(&self.data, self.pos + 1)); - self.next_state = Some(TokenizerState::AfterFunction); - TokenizerState::Junk - } - _ => return Err(PrefReaderError::new - ("Unexpected character after function argument", - self.position, - None)) + } + TokenizerState::AfterFunctionArg => match c { + ',' => { + token_data.start(&self, TokenType::Comma); + token_data.end(&self.data, self.pos + 1)?; + self.next_state = Some(TokenizerState::FunctionArg); + TokenizerState::Junk + } + ')' => { + token_data.start(&self, TokenType::Paren); + token_data.end(&self.data, self.pos + 1)?; + self.next_state = Some(TokenizerState::AfterFunction); + TokenizerState::Junk + } + _ => { + return Err(PrefReaderError::new( + "Unexpected character after function argument", + self.position, + None, + )) } }, - TokenizerState::AfterFunction => { - match c { - ';' => { - token_data.start(&self, TokenType::Semicolon); - try!(token_data.end(&self.data, self.pos)); - self.next_state = Some(TokenizerState::FunctionName); - TokenizerState::Junk - } - _ => return Err(PrefReaderError::new( + TokenizerState::AfterFunction => match c { + ';' => { + token_data.start(&self, TokenType::Semicolon); + token_data.end(&self.data, self.pos)?; + self.next_state = Some(TokenizerState::FunctionName); + TokenizerState::Junk + } + _ => { + return Err(PrefReaderError::new( "Unexpected character after function", - self.position, None)) + self.position, + None, + )) } }, - TokenizerState::Error => TokenizerState::Error + TokenizerState::Error => TokenizerState::Error, }; if token_data.complete { return Ok(Some(token_data)); @@ -722,10 +750,8 @@ impl<'a> Iterator for PrefTokenizer<'a> { let token_data = match self.next_token() { Err(e) => { self.state = TokenizerState::Error; - return Some(PrefToken::Error(e.message, - e.position)) - - }, + return Some(PrefToken::Error(e.message, e.position)); + } Ok(Some(token_data)) => token_data, Ok(None) => return None, }; @@ -751,23 +777,23 @@ pub fn serialize_token(token: &PrefToken, output: &mut T) -> Result<() data_buf.push_str(data.borrow()); data_buf.push_str("*"); &*data_buf - }, + } &PrefToken::CommentLine(ref data, _) => { data_buf.reserve(data.len() + 2); data_buf.push_str("//"); data_buf.push_str(data.borrow()); &*data_buf - }, + } &PrefToken::CommentBashLine(ref data, _) => { data_buf.reserve(data.len() + 1); data_buf.push_str("#"); data_buf.push_str(data.borrow()); &*data_buf - }, + } &PrefToken::Paren(data, _) => { data_buf.push(data); &*data_buf - }, + } &PrefToken::Comma(_) => ",", &PrefToken::Semicolon(_) => ";\n", &PrefToken::String(ref data, _) => { @@ -776,24 +802,31 @@ pub fn serialize_token(token: &PrefToken, output: &mut T) -> Result<() data_buf.push_str(escape_quote(data.borrow()).borrow()); data_buf.push('"'); &*data_buf - }, + } &PrefToken::Int(data, _) => { data_buf.push_str(&*data.to_string()); &*data_buf - }, + } &PrefToken::Bool(data, _) => { - if data {"true"} else {"false"} - }, - &PrefToken::Error(data, pos) => return Err(PrefReaderError::new(data, pos, None)) + if data { + "true" + } else { + "false" + } + } + &PrefToken::Error(data, pos) => return Err(PrefReaderError::new(data, pos, None)), }; - try!(output.write(data.as_bytes())); + output.write(data.as_bytes())?; Ok(()) } pub fn serialize_tokens<'a, I, W>(tokens: I, output: &mut W) -> Result<(), PrefReaderError> - where I: Iterator>, W: Write { +where + I: Iterator>, + W: Write, +{ for token in tokens { - try!(serialize_token(token, output)); + serialize_token(token, output)?; } Ok(()) } @@ -801,9 +834,7 @@ pub fn serialize_tokens<'a, I, W>(tokens: I, output: &mut W) -> Result<(), PrefR fn escape_quote<'a>(data: &'a str) -> Cow<'a, str> { // Not very efficient… if data.contains("\"") || data.contains("\\") { - let new_data = Cow::Owned(data - .replace(r#"\"#, r#"\\"#) - .replace(r#"""#, r#"\""#)); + let new_data = Cow::Owned(data.replace(r#"\"#, r#"\\"#).replace(r#"""#, r#"\""#)); new_data } else { Cow::Borrowed(data) @@ -820,7 +851,7 @@ enum ParserState { struct PrefBuilder { key: Option, value: Option, - sticky: bool + sticky: bool, } impl PrefBuilder { @@ -828,27 +859,24 @@ impl PrefBuilder { PrefBuilder { key: None, value: None, - sticky: false + sticky: false, } } } - fn skip_comments<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Option> { loop { match tokenizer.next() { - Some(PrefToken::CommentBashLine(_, _)) | - Some(PrefToken::CommentBlock(_, _)) | - Some(PrefToken::CommentLine(_, _)) => {}, + Some(PrefToken::CommentBashLine(_, _)) + | Some(PrefToken::CommentBlock(_, _)) + | Some(PrefToken::CommentLine(_, _)) => {} Some(x) => return Some(x), None => return None, } } } -pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result { - +pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result { let mut state = ParserState::Function; let mut current_pref = PrefBuilder::new(); let mut rv = Preferences::new(); @@ -859,19 +887,17 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result x, - None => break + None => break, } }; // First deal with comments and errors match token { PrefToken::Error(msg, position) => { return Err(PrefReaderError::new(msg.into(), position, None)); - }, - PrefToken::CommentBashLine(_, _) | - PrefToken::CommentLine(_, _) | - PrefToken::CommentBlock(_, _) => { - continue - }, + } + PrefToken::CommentBashLine(_, _) + | PrefToken::CommentLine(_, _) + | PrefToken::CommentBlock(_, _) => continue, _ => {} } state = match state { @@ -882,72 +908,89 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result { current_pref.sticky = false; - }, + } PrefToken::StickyPrefFunction(_) => { current_pref.sticky = true; - }, + } _ => { - return Err(PrefReaderError::new("Expected pref function".into(), - token.position(), None)); + return Err(PrefReaderError::new( + "Expected pref function".into(), + token.position(), + None, + )); } } let next = skip_comments(tokenizer); match next { Some(PrefToken::Paren('(', _)) => ParserState::Key, - _ => return Err(PrefReaderError::new("Expected open paren".into(), - next.map(|x| x.position()) - .unwrap_or(tokenizer.position), - None)) + _ => { + return Err(PrefReaderError::new( + "Expected open paren".into(), + next.map(|x| x.position()).unwrap_or(tokenizer.position), + None, + )) + } } - }, + } ParserState::Key => { match token { PrefToken::String(data, _) => current_pref.key = Some(data.into_owned()), _ => { - return Err(PrefReaderError::new("Expected string", token.position(), None)); + return Err(PrefReaderError::new( + "Expected string", + token.position(), + None, + )); } } let next = skip_comments(tokenizer); match next { Some(PrefToken::Comma(_)) => ParserState::Value, - _ => return Err(PrefReaderError::new("Expected comma", - next.map(|x| x.position()) - .unwrap_or(tokenizer.position), - None)) + _ => { + return Err(PrefReaderError::new( + "Expected comma", + next.map(|x| x.position()).unwrap_or(tokenizer.position), + None, + )) + } } - }, + } ParserState::Value => { match token { PrefToken::String(data, _) => { current_pref.value = Some(PrefValue::String(data.into_owned())) - }, - PrefToken::Int(data, _) => { - current_pref.value = Some(PrefValue::Int(data)) } - PrefToken::Bool(data, _) => { - current_pref.value = Some(PrefValue::Bool(data)) - }, + PrefToken::Int(data, _) => current_pref.value = Some(PrefValue::Int(data)), + PrefToken::Bool(data, _) => current_pref.value = Some(PrefValue::Bool(data)), _ => { - return Err(PrefReaderError::new("Expected value", token.position(), - None)) + return Err(PrefReaderError::new( + "Expected value", + token.position(), + None, + )) } } let next = skip_comments(tokenizer); match next { Some(PrefToken::Paren(')', _)) => {} - _ => return Err(PrefReaderError::new("Expected close paren", - next.map(|x| x.position()) - .unwrap_or(tokenizer.position), - None)) + _ => { + return Err(PrefReaderError::new( + "Expected close paren", + next.map(|x| x.position()).unwrap_or(tokenizer.position), + None, + )) + } } let next = skip_comments(tokenizer); match next { - Some(PrefToken::Semicolon(_)) | - None => {}, - _ => return Err(PrefReaderError::new("Expected semicolon", - next.map(|x| x.position()) - .unwrap_or(tokenizer.position), - None)) + Some(PrefToken::Semicolon(_)) | None => {} + _ => { + return Err(PrefReaderError::new( + "Expected semicolon", + next.map(|x| x.position()).unwrap_or(tokenizer.position), + None, + )) + } } let key = mem::replace(&mut current_pref.key, None); let value = mem::replace(&mut current_pref.value, None); @@ -959,14 +1002,17 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result { - return Err(PrefReaderError::new("EOF in middle of function", - tokenizer.position, None)); - }, + return Err(PrefReaderError::new( + "EOF in middle of function", + tokenizer.position, + None, + )); + } _ => {} } Ok(rv) @@ -981,26 +1027,26 @@ pub fn serialize(prefs: &Preferences, output: &mut W) -> io::Result<() } else { "user_pref(" }.as_bytes(); - try!(output.write(func)); - try!(output.write("\"".as_bytes())); - try!(output.write(escape_quote(key).as_bytes())); - try!(output.write("\"".as_bytes())); - try!(output.write(", ".as_bytes())); + output.write(func)?; + output.write("\"".as_bytes())?; + output.write(escape_quote(key).as_bytes())?; + output.write("\"".as_bytes())?; + output.write(", ".as_bytes())?; match pref.value { PrefValue::Bool(x) => { - try!(output.write((if x {"true"} else {"false"}).as_bytes())); - }, + output.write((if x { "true" } else { "false" }).as_bytes())?; + } PrefValue::Int(x) => { - try!(output.write(x.to_string().as_bytes())); - }, + output.write(x.to_string().as_bytes())?; + } PrefValue::String(ref x) => { - try!(output.write("\"".as_bytes())); - try!(output.write(escape_quote(x).as_bytes())); - try!(output.write("\"".as_bytes())); + output.write("\"".as_bytes())?; + output.write(escape_quote(x).as_bytes())?; + output.write("\"".as_bytes())?; } }; - try!(output.write(");\n".as_bytes())); - }; + output.write(");\n".as_bytes())?; + } Ok(()) } diff --git a/testing/mozbase/rust/mozprofile/src/profile.rs b/testing/mozbase/rust/mozprofile/src/profile.rs index d38f50d1fde6..11b342c1a2ab 100644 --- a/testing/mozbase/rust/mozprofile/src/profile.rs +++ b/testing/mozbase/rust/mozprofile/src/profile.rs @@ -1,9 +1,9 @@ -use preferences::{Preferences, Pref}; +use preferences::{Pref, Preferences}; use prefreader::{parse, serialize, PrefReaderError}; use std::collections::btree_map::Iter; use std::fs::File; -use std::io::Result as IoResult; use std::io::prelude::*; +use std::io::Result as IoResult; use std::path::{Path, PathBuf}; use tempdir::TempDir; @@ -21,7 +21,7 @@ impl Profile { let path = match opt_path { Some(p) => p.to_path_buf(), None => { - let dir = try!(TempDir::new("rust_mozprofile")); + let dir = TempDir::new("rust_mozprofile")?; let temp_path = dir.path().to_path_buf(); temp_dir = Some(dir); temp_path @@ -32,7 +32,7 @@ impl Profile { path: path, temp_dir: temp_dir, prefs: None, - user_prefs: None + user_prefs: None, }) } @@ -40,7 +40,7 @@ impl Profile { if self.prefs.is_none() { let mut pref_path = PathBuf::from(&self.path); pref_path.push("prefs.js"); - self.prefs = Some(try!(PrefFile::new(pref_path))) + self.prefs = Some(PrefFile::new(pref_path)?) }; // This error handling doesn't make much sense Ok(self.prefs.as_mut().unwrap()) @@ -50,7 +50,7 @@ impl Profile { if self.user_prefs.is_none() { let mut pref_path = PathBuf::from(&self.path); pref_path.push("user.js"); - self.user_prefs = Some(try!(PrefFile::new(pref_path))) + self.user_prefs = Some(PrefFile::new(pref_path)?) }; // This error handling doesn't make much sense Ok(self.user_prefs.as_mut().unwrap()) @@ -68,32 +68,36 @@ impl PrefFile { let prefs = if !path.exists() { Preferences::new() } else { - let mut f = try!(File::open(&path)); + let mut f = File::open(&path)?; let mut buf = String::with_capacity(4096); - try!(f.read_to_string(&mut buf)); - try!(parse(buf.as_bytes())) + f.read_to_string(&mut buf)?; + parse(buf.as_bytes())? }; Ok(PrefFile { path: path, - prefs: prefs + prefs: prefs, }) } pub fn write(&self) -> IoResult<()> { - let mut f = try!(File::create(&self.path)); + let mut f = File::create(&self.path)?; serialize(&self.prefs, &mut f) } pub fn insert_slice(&mut self, preferences: &[(K, Pref)]) - where K: Into + Clone { + where + K: Into + Clone, + { for &(ref name, ref value) in preferences.iter() { self.insert((*name).clone(), (*value).clone()); } } pub fn insert(&mut self, key: K, value: Pref) - where K: Into { + where + K: Into, + { self.prefs.insert(key.into(), value); } From 4cf5f38cc9f9b5eeeffec8d78ae1401d3af4d68f Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:35:36 +0100 Subject: [PATCH 19/80] Bug 1488006: mozprofile: avoid redundant field names in struct init; r=jgraham --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 14 +++++++------- testing/mozbase/rust/mozprofile/src/profile.rs | 9 +++------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 5c6dffbe9d63..39b88612ec47 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -17,9 +17,9 @@ impl PrefReaderError { parent: Option>, ) -> PrefReaderError { PrefReaderError { - message: message, - position: position, - parent: parent, + message, + position, + parent, } } } @@ -157,11 +157,11 @@ struct TokenData<'a> { impl<'a> TokenData<'a> { fn new(token_type: TokenType, position: Position, start_pos: usize) -> TokenData<'a> { TokenData { - token_type: token_type, + token_type, complete: false, - position: position, + position, data: Cow::Borrowed(""), - start_pos: start_pos, + start_pos, } } @@ -213,7 +213,7 @@ pub struct PrefTokenizer<'a> { impl<'a> PrefTokenizer<'a> { pub fn new(data: &'a [u8]) -> PrefTokenizer<'a> { PrefTokenizer { - data: data, + data, pos: 0, cur: None, position: Position::new(), diff --git a/testing/mozbase/rust/mozprofile/src/profile.rs b/testing/mozbase/rust/mozprofile/src/profile.rs index 11b342c1a2ab..38d4cccb0092 100644 --- a/testing/mozbase/rust/mozprofile/src/profile.rs +++ b/testing/mozbase/rust/mozprofile/src/profile.rs @@ -29,8 +29,8 @@ impl Profile { }; Ok(Profile { - path: path, - temp_dir: temp_dir, + path, + temp_dir, prefs: None, user_prefs: None, }) @@ -74,10 +74,7 @@ impl PrefFile { parse(buf.as_bytes())? }; - Ok(PrefFile { - path: path, - prefs: prefs, - }) + Ok(PrefFile { path, prefs }) } pub fn write(&self) -> IoResult<()> { From da30cf1fa1fc8012b58ced35839ad0e9d83d6f59 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:39:30 +0100 Subject: [PATCH 20/80] Bug 1488006: mozprofile: drop needless lifetimes; r=jgraham Drops all the unnecessary lifetime definitions in mozprofile. --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 39b88612ec47..08ff4cb4f1ca 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -760,7 +760,7 @@ impl<'a> Iterator for PrefTokenizer<'a> { } } -pub fn tokenize<'a>(data: &'a [u8]) -> PrefTokenizer<'a> { +pub fn tokenize(data: &[u8]) -> PrefTokenizer { PrefTokenizer::new(data) } @@ -831,7 +831,7 @@ where Ok(()) } -fn escape_quote<'a>(data: &'a str) -> Cow<'a, str> { +fn escape_quote(data: &str) -> Cow { // Not very efficient… if data.contains("\"") || data.contains("\\") { let new_data = Cow::Owned(data.replace(r#"\"#, r#"\\"#).replace(r#"""#, r#"\""#)); @@ -1050,7 +1050,7 @@ pub fn serialize(prefs: &Preferences, output: &mut W) -> io::Result<() Ok(()) } -pub fn parse<'a>(data: &'a [u8]) -> Result { +pub fn parse(data: &[u8]) -> Result { let mut tokenizer = tokenize(data); parse_tokens(&mut tokenizer) } From 70d1acfb74f807d73dcb6cd1b1090a4965a310d5 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:44:09 +0100 Subject: [PATCH 21/80] Bug 1488006: mozprofile: prefer byte string literals to as_bytes() where possible; r=jgraham Where string literals contain only ASCII characters, it is considered better style to define byte strings using b"foo" rather than calling "foo".as_bytes(). --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 08ff4cb4f1ca..72908b36fe63 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -1028,24 +1028,24 @@ pub fn serialize(prefs: &Preferences, output: &mut W) -> io::Result<() "user_pref(" }.as_bytes(); output.write(func)?; - output.write("\"".as_bytes())?; + output.write(b"\"")?; output.write(escape_quote(key).as_bytes())?; - output.write("\"".as_bytes())?; - output.write(", ".as_bytes())?; + output.write(b"\"")?; + output.write(b", ")?; match pref.value { PrefValue::Bool(x) => { - output.write((if x { "true" } else { "false" }).as_bytes())?; + output.write(if x { b"true" } else { b"false" })?; } PrefValue::Int(x) => { output.write(x.to_string().as_bytes())?; } PrefValue::String(ref x) => { - output.write("\"".as_bytes())?; + output.write(b"\"")?; output.write(escape_quote(x).as_bytes())?; - output.write("\"".as_bytes())?; + output.write(b"\"")?; } }; - output.write(");\n".as_bytes())?; + output.write(b");\n")?; } Ok(()) } From 129ea5a2a5e0be28b15cb4bc8ecee8537f0878e4 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:47:11 +0100 Subject: [PATCH 22/80] Bug 1488006: mozprofile: replace call to io::Write::write() with ::write_all(); r=jgraham io::Write::write() is not guaranteed to process the entire buffer. It returns how many bytes were processed, which may be smaller than the given buffer's length. mozprofile does not need to deal with partial writes, so all the calls to ::write() may be replaced with ::write_all(). --- .../mozbase/rust/mozprofile/src/prefreader.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 72908b36fe63..0c16c0d8f49f 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -816,7 +816,7 @@ pub fn serialize_token(token: &PrefToken, output: &mut T) -> Result<() } &PrefToken::Error(data, pos) => return Err(PrefReaderError::new(data, pos, None)), }; - output.write(data.as_bytes())?; + output.write_all(data.as_bytes())?; Ok(()) } @@ -1027,25 +1027,25 @@ pub fn serialize(prefs: &Preferences, output: &mut W) -> io::Result<() } else { "user_pref(" }.as_bytes(); - output.write(func)?; - output.write(b"\"")?; - output.write(escape_quote(key).as_bytes())?; - output.write(b"\"")?; - output.write(b", ")?; + output.write_all(func)?; + output.write_all(b"\"")?; + output.write_all(escape_quote(key).as_bytes())?; + output.write_all(b"\"")?; + output.write_all(b", ")?; match pref.value { PrefValue::Bool(x) => { - output.write(if x { b"true" } else { b"false" })?; + output.write_all(if x { b"true" } else { b"false" })?; } PrefValue::Int(x) => { - output.write(x.to_string().as_bytes())?; + output.write_all(x.to_string().as_bytes())?; } PrefValue::String(ref x) => { - output.write(b"\"")?; - output.write(escape_quote(x).as_bytes())?; - output.write(b"\"")?; + output.write_all(b"\"")?; + output.write_all(escape_quote(x).as_bytes())?; + output.write_all(b"\"")?; } }; - output.write(b");\n")?; + output.write_all(b");\n")?; } Ok(()) } From 5c6ca540e3bd5919291af737eb3d670731499a7a Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:50:10 +0100 Subject: [PATCH 23/80] Bug 1488006: mozprofile: loop over references to container; r=jgraham It is considered more idiomatic Rust to loop over references to containers rather than calling the iteration protocol's x.iter() or x.into_iter() explicitly. --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 0c16c0d8f49f..dec63b31ba0a 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -1021,7 +1021,7 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result(prefs: &Preferences, output: &mut W) -> io::Result<()> { let mut p: Vec<_> = prefs.iter().collect(); p.sort_by(|a, b| a.0.cmp(&b.0)); - for &(key, pref) in p.iter() { + for &(key, pref) in &p { let func = if pref.sticky { "sticky_pref(" } else { From cc5b563e285394e251a9d684667f8609690bc7bd Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:52:08 +0100 Subject: [PATCH 24/80] Bug 1488006: mozprofile: avoid identical conversions; r=jgraham PrefReaderError::new already expects a &str. --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index dec63b31ba0a..8fdde5096a1e 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -893,7 +893,7 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result { - return Err(PrefReaderError::new(msg.into(), position, None)); + return Err(PrefReaderError::new(msg, position, None)); } PrefToken::CommentBashLine(_, _) | PrefToken::CommentLine(_, _) @@ -914,7 +914,7 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result { return Err(PrefReaderError::new( - "Expected pref function".into(), + "Expected pref function", token.position(), None, )); @@ -925,7 +925,7 @@ pub fn parse_tokens<'a>(tokenizer: &mut PrefTokenizer<'a>) -> Result ParserState::Key, _ => { return Err(PrefReaderError::new( - "Expected open paren".into(), + "Expected open paren", next.map(|x| x.position()).unwrap_or(tokenizer.position), None, )) From 3a22b09028bdf6eb47de6233b62a7c476ad158a2 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:54:49 +0100 Subject: [PATCH 25/80] Bug 1488006: mozprofile: turn single-character strings into chars; r=jgraham Where we have single-character strings we can convert them to chars for efficiency. --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 8fdde5096a1e..79ad06e0d955 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -833,9 +833,8 @@ where fn escape_quote(data: &str) -> Cow { // Not very efficient… - if data.contains("\"") || data.contains("\\") { - let new_data = Cow::Owned(data.replace(r#"\"#, r#"\\"#).replace(r#"""#, r#"\""#)); - new_data + if data.contains('"') || data.contains('\\') { + Cow::Owned(data.replace(r#"\"#, r#"\\"#).replace(r#"""#, r#"\""#)) } else { Cow::Borrowed(data) } From 5f5116a9ecf7a900ad0276c6478bf0d1045d124c Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:56:31 +0100 Subject: [PATCH 26/80] Bug 1488006: mozprofile: deref token to avoid & prefix; r=jgraham It is considered more idiomatic to dereference the match expression than to peek at each variant through a reference. This silences a clippy lint warning. --- .../mozbase/rust/mozprofile/src/prefreader.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 79ad06e0d955..3818c590aadd 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -767,54 +767,54 @@ pub fn tokenize(data: &[u8]) -> PrefTokenizer { pub fn serialize_token(token: &PrefToken, output: &mut T) -> Result<(), PrefReaderError> { let mut data_buf = String::new(); - let data = match token { - &PrefToken::PrefFunction(_) => "pref", - &PrefToken::UserPrefFunction(_) => "user_pref", - &PrefToken::StickyPrefFunction(_) => "sticky_pref", - &PrefToken::CommentBlock(ref data, _) => { + let data = match *token { + PrefToken::PrefFunction(_) => "pref", + PrefToken::UserPrefFunction(_) => "user_pref", + PrefToken::StickyPrefFunction(_) => "sticky_pref", + PrefToken::CommentBlock(ref data, _) => { data_buf.reserve(data.len() + 4); data_buf.push_str("/*"); data_buf.push_str(data.borrow()); data_buf.push_str("*"); &*data_buf } - &PrefToken::CommentLine(ref data, _) => { + PrefToken::CommentLine(ref data, _) => { data_buf.reserve(data.len() + 2); data_buf.push_str("//"); data_buf.push_str(data.borrow()); &*data_buf } - &PrefToken::CommentBashLine(ref data, _) => { + PrefToken::CommentBashLine(ref data, _) => { data_buf.reserve(data.len() + 1); data_buf.push_str("#"); data_buf.push_str(data.borrow()); &*data_buf } - &PrefToken::Paren(data, _) => { + PrefToken::Paren(data, _) => { data_buf.push(data); &*data_buf } - &PrefToken::Comma(_) => ",", - &PrefToken::Semicolon(_) => ";\n", - &PrefToken::String(ref data, _) => { + PrefToken::Comma(_) => ",", + PrefToken::Semicolon(_) => ";\n", + PrefToken::String(ref data, _) => { data_buf.reserve(data.len() + 2); data_buf.push('"'); data_buf.push_str(escape_quote(data.borrow()).borrow()); data_buf.push('"'); &*data_buf } - &PrefToken::Int(data, _) => { + PrefToken::Int(data, _) => { data_buf.push_str(&*data.to_string()); &*data_buf } - &PrefToken::Bool(data, _) => { + PrefToken::Bool(data, _) => { if data { "true" } else { "false" } } - &PrefToken::Error(data, pos) => return Err(PrefReaderError::new(data, pos, None)), + PrefToken::Error(data, pos) => return Err(PrefReaderError::new(data, pos, None)), }; output.write_all(data.as_bytes())?; Ok(()) From ea994573f09ef8aed9e3c38dfe1fad6237c5a8ff Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sat, 1 Sep 2018 16:59:16 +0100 Subject: [PATCH 27/80] Bug 1488006: mozprofile: avoid incidental functional call; r=jgraham There is a functional call after ok_or() which is called and evaluated before escape_char is converted due to RHS evaluation. We can avoid this by employing a closure with ok_or_else(). --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 3818c590aadd..2f1ebc7933a3 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -346,9 +346,9 @@ impl<'a> PrefTokenizer<'a> { )) } }; - Ok(Some(char::from_u32(escape_char).ok_or( - PrefReaderError::new("Invalid codepoint decoded from escape", self.position, None), - )?)) + Ok(Some(char::from_u32(escape_char).ok_or_else(|| { + PrefReaderError::new("Invalid codepoint decoded from escape", self.position, None) + })?)) } fn read_hex_escape(&mut self, hex_chars: isize, first: bool) -> Result { From c67e2dd1989e73b57e0b90d01d16edc7e8eefd66 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Tue, 4 Sep 2018 13:53:17 +0100 Subject: [PATCH 28/80] Bug 1488006: mozprofile: derive Default for prefreader::Position. r=jgraham The user might expect to be able to use Default as the type can be constructed without arguments. --- testing/mozbase/rust/mozprofile/src/prefreader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs index 2f1ebc7933a3..662d13648ce0 100644 --- a/testing/mozbase/rust/mozprofile/src/prefreader.rs +++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs @@ -72,7 +72,7 @@ enum TokenizerState { Error, } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Position { line: u32, column: u32, From abcd838ffb2d22040b2d71a9c35a710f52fe1e15 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 4 Sep 2018 09:32:38 -0400 Subject: [PATCH 29/80] Bug 1488420 - Update pdf.js to version 2.0.813. r=bdahl --- browser/extensions/pdfjs/README.mozilla | 4 +- .../pdfjs/content/PdfJsDefaultPreferences.jsm | 9 +- browser/extensions/pdfjs/content/build/pdf.js | 987 ++++--- .../pdfjs/content/build/pdf.worker.js | 2294 +++++++++-------- .../extensions/pdfjs/content/web/viewer.js | 91 +- browser/extensions/pdfjs/moz.yaml | 2 +- 6 files changed, 1721 insertions(+), 1666 deletions(-) diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index fb359a5f9a8f..0f0450636446 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,5 +1,5 @@ This is the PDF.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 2.0.775 +Current extension version is: 2.0.813 -Taken from upstream commit: 20cd1b35 +Taken from upstream commit: af89ec27 diff --git a/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm b/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm index 337d4299b301..7fede18a30fb 100644 --- a/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm +++ b/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm @@ -1,4 +1,4 @@ -/* Copyright 2017 Mozilla Foundation +/* Copyright 2018 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,10 @@ * limitations under the License. */ +/* eslint-disable */ + // -// THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT MANUALLY! +// THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT MANUALLY! // "use strict"; @@ -25,6 +27,7 @@ var PdfJsDefaultPreferences = Object.freeze({ "sidebarViewOnLoad": 0, "cursorToolOnLoad": 0, "enableWebGL": false, + "eventBusDispatchToDOM": false, "pdfBugEnabled": false, "disableRange": false, "disableStream": false, @@ -39,5 +42,5 @@ var PdfJsDefaultPreferences = Object.freeze({ "disablePageMode": false, "disablePageLabels": false, "scrollModeOnLoad": 0, - "spreadModeOnLoad": 0, + "spreadModeOnLoad": 0 }); diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index c6d6630bcfd2..f12d1562dde1 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2017 Mozilla Foundation + * Copyright 2018 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -var pdfjsVersion = '2.0.775'; -var pdfjsBuild = '20cd1b35'; +var pdfjsVersion = '2.0.813'; +var pdfjsBuild = 'af89ec27'; var pdfjsSharedUtil = __w_pdfjs_require__(1); var pdfjsDisplayAPI = __w_pdfjs_require__(7); var pdfjsDisplayTextLayer = __w_pdfjs_require__(19); @@ -177,7 +177,7 @@ exports.apiCompatibilityParams = pdfjsDisplayAPICompatibility.apiCompatibilityPa Object.defineProperty(exports, "__esModule", { value: true }); -exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; +exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; __w_pdfjs_require__(2); @@ -191,6 +191,16 @@ const NativeImageDecoding = { DECODE: 'decode', DISPLAY: 'display' }; +const PermissionFlag = { + PRINT: 0x04, + MODIFY_CONTENTS: 0x08, + COPY: 0x10, + MODIFY_ANNOTATIONS: 0x20, + FILL_INTERACTIVE_FORMS: 0x100, + COPY_FOR_ACCESSIBILITY: 0x200, + ASSEMBLE: 0x400, + PRINT_HIGH_QUALITY: 0x800 +}; var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -913,6 +923,7 @@ exports.MissingPDFException = MissingPDFException; exports.NativeImageDecoding = NativeImageDecoding; exports.PasswordException = PasswordException; exports.PasswordResponses = PasswordResponses; +exports.PermissionFlag = PermissionFlag; exports.StreamType = StreamType; exports.TextRenderingMode = TextRenderingMode; exports.UnexpectedResponseException = UnexpectedResponseException; @@ -4215,7 +4226,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { } return worker.messageHandler.sendWithPromise('GetDocRequest', { docId, - apiVersion: '2.0.775', + apiVersion: '2.0.813', source: { data: source.data, url: source.url, @@ -4323,70 +4334,70 @@ var PDFDataRangeTransport = function pdfDataRangeTransportClosure() { }; return PDFDataRangeTransport; }(); -var PDFDocumentProxy = function PDFDocumentProxyClosure() { - function PDFDocumentProxy(pdfInfo, transport, loadingTask) { - this._pdfInfo = pdfInfo; - this.transport = transport; +class PDFDocumentProxy { + constructor(pdfInfo, transport, loadingTask) { this.loadingTask = loadingTask; + this._pdfInfo = pdfInfo; + this._transport = transport; } - PDFDocumentProxy.prototype = { - get numPages() { - return this._pdfInfo.numPages; - }, - get fingerprint() { - return this._pdfInfo.fingerprint; - }, - getPage(pageNumber) { - return this.transport.getPage(pageNumber); - }, - getPageIndex: function PDFDocumentProxy_getPageIndex(ref) { - return this.transport.getPageIndex(ref); - }, - getDestinations: function PDFDocumentProxy_getDestinations() { - return this.transport.getDestinations(); - }, - getDestination: function PDFDocumentProxy_getDestination(id) { - return this.transport.getDestination(id); - }, - getPageLabels: function PDFDocumentProxy_getPageLabels() { - return this.transport.getPageLabels(); - }, - getPageMode() { - return this.transport.getPageMode(); - }, - getAttachments: function PDFDocumentProxy_getAttachments() { - return this.transport.getAttachments(); - }, - getJavaScript() { - return this.transport.getJavaScript(); - }, - getOutline: function PDFDocumentProxy_getOutline() { - return this.transport.getOutline(); - }, - getMetadata: function PDFDocumentProxy_getMetadata() { - return this.transport.getMetadata(); - }, - getData: function PDFDocumentProxy_getData() { - return this.transport.getData(); - }, - getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() { - return this.transport.downloadInfoCapability.promise; - }, - getStats: function PDFDocumentProxy_getStats() { - return this.transport.getStats(); - }, - cleanup: function PDFDocumentProxy_cleanup() { - this.transport.startCleanup(); - }, - destroy: function PDFDocumentProxy_destroy() { - return this.loadingTask.destroy(); - }, - get loadingParams() { - return this.transport.loadingParams; - } - }; - return PDFDocumentProxy; -}(); + get numPages() { + return this._pdfInfo.numPages; + } + get fingerprint() { + return this._pdfInfo.fingerprint; + } + getPage(pageNumber) { + return this._transport.getPage(pageNumber); + } + getPageIndex(ref) { + return this._transport.getPageIndex(ref); + } + getDestinations() { + return this._transport.getDestinations(); + } + getDestination(id) { + return this._transport.getDestination(id); + } + getPageLabels() { + return this._transport.getPageLabels(); + } + getPageMode() { + return this._transport.getPageMode(); + } + getAttachments() { + return this._transport.getAttachments(); + } + getJavaScript() { + return this._transport.getJavaScript(); + } + getOutline() { + return this._transport.getOutline(); + } + getPermissions() { + return this._transport.getPermissions(); + } + getMetadata() { + return this._transport.getMetadata(); + } + getData() { + return this._transport.getData(); + } + getDownloadInfo() { + return this._transport.downloadInfoCapability.promise; + } + getStats() { + return this._transport.getStats(); + } + cleanup() { + this._transport.startCleanup(); + } + destroy() { + return this.loadingTask.destroy(); + } + get loadingParams() { + return this._transport.loadingParams; + } +} var PDFPageProxy = function PDFPageProxyClosure() { function PDFPageProxy(pageIndex, pageInfo, transport, pdfBug = false) { this.pageIndex = pageIndex; @@ -4900,8 +4911,8 @@ var PDFWorker = function PDFWorkerClosure() { }; return PDFWorker; }(); -var WorkerTransport = function WorkerTransportClosure() { - function WorkerTransport(messageHandler, loadingTask, networkStream, params) { +class WorkerTransport { + constructor(messageHandler, loadingTask, networkStream, params) { this.messageHandler = messageHandler; this.loadingTask = loadingTask; this.commonObjs = new PDFObjects(); @@ -4922,446 +4933,430 @@ var WorkerTransport = function WorkerTransportClosure() { this.downloadInfoCapability = (0, _util.createPromiseCapability)(); this.setupMessageHandler(); } - WorkerTransport.prototype = { - destroy: function WorkerTransport_destroy() { - if (this.destroyCapability) { - return this.destroyCapability.promise; - } - this.destroyed = true; - this.destroyCapability = (0, _util.createPromiseCapability)(); - if (this._passwordCapability) { - this._passwordCapability.reject(new Error('Worker was destroyed during onPassword callback')); - } - var waitOn = []; - this.pageCache.forEach(function (page) { - if (page) { - waitOn.push(page._destroy()); - } - }); - this.pageCache = []; - this.pagePromises = []; - var terminated = this.messageHandler.sendWithPromise('Terminate', null); - waitOn.push(terminated); - Promise.all(waitOn).then(() => { - this.fontLoader.clear(); - if (this._networkStream) { - this._networkStream.cancelAllRequests(); - } - if (this.messageHandler) { - this.messageHandler.destroy(); - this.messageHandler = null; - } - this.destroyCapability.resolve(); - }, this.destroyCapability.reject); + destroy() { + if (this.destroyCapability) { return this.destroyCapability.promise; - }, - setupMessageHandler: function WorkerTransport_setupMessageHandler() { - var messageHandler = this.messageHandler; - var loadingTask = this.loadingTask; - messageHandler.on('GetReader', function (data, sink) { - (0, _util.assert)(this._networkStream); - this._fullReader = this._networkStream.getFullReader(); - this._fullReader.onProgress = evt => { - this._lastProgress = { - loaded: evt.loaded, - total: evt.total - }; + } + this.destroyed = true; + this.destroyCapability = (0, _util.createPromiseCapability)(); + if (this._passwordCapability) { + this._passwordCapability.reject(new Error('Worker was destroyed during onPassword callback')); + } + const waitOn = []; + this.pageCache.forEach(function (page) { + if (page) { + waitOn.push(page._destroy()); + } + }); + this.pageCache = []; + this.pagePromises = []; + const terminated = this.messageHandler.sendWithPromise('Terminate', null); + waitOn.push(terminated); + Promise.all(waitOn).then(() => { + this.fontLoader.clear(); + if (this._networkStream) { + this._networkStream.cancelAllRequests(); + } + if (this.messageHandler) { + this.messageHandler.destroy(); + this.messageHandler = null; + } + this.destroyCapability.resolve(); + }, this.destroyCapability.reject); + return this.destroyCapability.promise; + } + setupMessageHandler() { + const { messageHandler, loadingTask } = this; + messageHandler.on('GetReader', function (data, sink) { + (0, _util.assert)(this._networkStream); + this._fullReader = this._networkStream.getFullReader(); + this._fullReader.onProgress = evt => { + this._lastProgress = { + loaded: evt.loaded, + total: evt.total }; - sink.onPull = () => { - this._fullReader.read().then(function ({ value, done }) { - if (done) { - sink.close(); - return; - } - (0, _util.assert)((0, _util.isArrayBuffer)(value)); - sink.enqueue(new Uint8Array(value), 1, [value]); - }).catch(reason => { - sink.error(reason); - }); - }; - sink.onCancel = reason => { - this._fullReader.cancel(reason); - }; - }, this); - messageHandler.on('ReaderHeadersReady', function (data) { - let headersCapability = (0, _util.createPromiseCapability)(); - let fullReader = this._fullReader; - fullReader.headersReady.then(() => { - if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { - if (this._lastProgress) { - let loadingTask = this.loadingTask; - if (loadingTask.onProgress) { - loadingTask.onProgress(this._lastProgress); - } - } - fullReader.onProgress = evt => { - let loadingTask = this.loadingTask; - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: evt.loaded, - total: evt.total - }); - } - }; + }; + sink.onPull = () => { + this._fullReader.read().then(function ({ value, done }) { + if (done) { + sink.close(); + return; } - headersCapability.resolve({ - isStreamingSupported: fullReader.isStreamingSupported, - isRangeSupported: fullReader.isRangeSupported, - contentLength: fullReader.contentLength - }); - }, headersCapability.reject); - return headersCapability.promise; - }, this); - messageHandler.on('GetRangeReader', function (data, sink) { - (0, _util.assert)(this._networkStream); - let _rangeReader = this._networkStream.getRangeReader(data.begin, data.end); - sink.onPull = () => { - _rangeReader.read().then(function ({ value, done }) { - if (done) { - sink.close(); - return; - } - (0, _util.assert)((0, _util.isArrayBuffer)(value)); - sink.enqueue(new Uint8Array(value), 1, [value]); - }).catch(reason => { - sink.error(reason); - }); - }; - sink.onCancel = reason => { - _rangeReader.cancel(reason); - }; - }, this); - messageHandler.on('GetDoc', function transportDoc({ pdfInfo }) { - this.numPages = pdfInfo.numPages; - var loadingTask = this.loadingTask; - var pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); - this.pdfDocument = pdfDocument; - loadingTask._capability.resolve(pdfDocument); - }, this); - messageHandler.on('PasswordRequest', function transportPasswordRequest(exception) { - this._passwordCapability = (0, _util.createPromiseCapability)(); - if (loadingTask.onPassword) { - var updatePassword = password => { - this._passwordCapability.resolve({ password }); - }; - try { - loadingTask.onPassword(updatePassword, exception.code); - } catch (ex) { - this._passwordCapability.reject(ex); - } - } else { - this._passwordCapability.reject(new _util.PasswordException(exception.message, exception.code)); - } - return this._passwordCapability.promise; - }, this); - messageHandler.on('PasswordException', function transportPasswordException(exception) { - loadingTask._capability.reject(new _util.PasswordException(exception.message, exception.code)); - }, this); - messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) { - this.loadingTask._capability.reject(new _util.InvalidPDFException(exception.message)); - }, this); - messageHandler.on('MissingPDF', function transportMissingPDF(exception) { - this.loadingTask._capability.reject(new _util.MissingPDFException(exception.message)); - }, this); - messageHandler.on('UnexpectedResponse', function transportUnexpectedResponse(exception) { - this.loadingTask._capability.reject(new _util.UnexpectedResponseException(exception.message, exception.status)); - }, this); - messageHandler.on('UnknownError', function transportUnknownError(exception) { - this.loadingTask._capability.reject(new _util.UnknownErrorException(exception.message, exception.details)); - }, this); - messageHandler.on('DataLoaded', function transportPage(data) { - this.downloadInfoCapability.resolve(data); - }, this); - messageHandler.on('StartRenderPage', function transportRender(data) { - if (this.destroyed) { - return; - } - var page = this.pageCache[data.pageIndex]; - page._stats.timeEnd('Page Request'); - page._startRenderPage(data.transparency, data.intent); - }, this); - messageHandler.on('RenderPageChunk', function transportRender(data) { - if (this.destroyed) { - return; - } - var page = this.pageCache[data.pageIndex]; - page._renderPageChunk(data.operatorList, data.intent); - }, this); - messageHandler.on('commonobj', function transportObj(data) { - if (this.destroyed) { - return; - } - var id = data[0]; - var type = data[1]; - if (this.commonObjs.hasData(id)) { - return; - } - switch (type) { - case 'Font': - var exportedData = data[2]; - let params = this._params; - if ('error' in exportedData) { - var exportedError = exportedData.error; - (0, _util.warn)('Error during font loading: ' + exportedError); - this.commonObjs.resolve(id, exportedError); - break; - } - var fontRegistry = null; - if (params.pdfBug && _global_scope2.default.FontInspector && _global_scope2.default.FontInspector.enabled) { - fontRegistry = { - registerFont(font, url) { - _global_scope2.default['FontInspector'].fontAdded(font, url); - } - }; - } - var font = new _font_loader.FontFaceObject(exportedData, { - isEvalSupported: params.isEvalSupported, - disableFontFace: params.disableFontFace, - ignoreErrors: params.ignoreErrors, - onUnsupportedFeature: this._onUnsupportedFeature.bind(this), - fontRegistry - }); - var fontReady = fontObjs => { - this.commonObjs.resolve(id, font); - }; - this.fontLoader.bind([font], fontReady); - break; - case 'FontPath': - this.commonObjs.resolve(id, data[2]); - break; - default: - throw new Error(`Got unknown common object type ${type}`); - } - }, this); - messageHandler.on('obj', function transportObj(data) { - if (this.destroyed) { - return; - } - var id = data[0]; - var pageIndex = data[1]; - var type = data[2]; - var pageProxy = this.pageCache[pageIndex]; - var imageData; - if (pageProxy.objs.hasData(id)) { - return; - } - switch (type) { - case 'JpegStream': - imageData = data[3]; - return new Promise((resolve, reject) => { - const img = new Image(); - img.onload = function () { - resolve(img); - }; - img.onerror = function () { - reject(new Error('Error during JPEG image loading')); - }; - img.src = imageData; - }).then(img => { - pageProxy.objs.resolve(id, img); - }); - case 'Image': - imageData = data[3]; - pageProxy.objs.resolve(id, imageData); - var MAX_IMAGE_SIZE_TO_STORE = 8000000; - if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { - pageProxy.cleanupAfterRender = true; - } - break; - default: - throw new Error(`Got unknown object type ${type}`); - } - }, this); - messageHandler.on('DocProgress', function transportDocProgress(data) { - if (this.destroyed) { - return; - } - var loadingTask = this.loadingTask; - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: data.loaded, - total: data.total - }); - } - }, this); - messageHandler.on('PageError', function transportError(data) { - if (this.destroyed) { - return; - } - var page = this.pageCache[data.pageNum - 1]; - var intentState = page.intentStates[data.intent]; - if (intentState.displayReadyCapability) { - intentState.displayReadyCapability.reject(data.error); - } else { - throw new Error(data.error); - } - if (intentState.operatorList) { - intentState.operatorList.lastChunk = true; - for (var i = 0; i < intentState.renderTasks.length; i++) { - intentState.renderTasks[i].operatorListChanged(); - } - } - }, this); - messageHandler.on('UnsupportedFeature', this._onUnsupportedFeature, this); - messageHandler.on('JpegDecode', function (data) { - if (this.destroyed) { - return Promise.reject(new Error('Worker was destroyed')); - } - if (typeof document === 'undefined') { - return Promise.reject(new Error('"document" is not defined.')); - } - var imageUrl = data[0]; - var components = data[1]; - if (components !== 3 && components !== 1) { - return Promise.reject(new Error('Only 3 components or 1 component can be returned')); - } - return new Promise(function (resolve, reject) { - var img = new Image(); - img.onload = function () { - var width = img.width; - var height = img.height; - var size = width * height; - var rgbaLength = size * 4; - var buf = new Uint8ClampedArray(size * components); - var tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = width; - tmpCanvas.height = height; - var tmpCtx = tmpCanvas.getContext('2d'); - tmpCtx.drawImage(img, 0, 0); - var data = tmpCtx.getImageData(0, 0, width, height).data; - var i, j; - if (components === 3) { - for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { - buf[j] = data[i]; - buf[j + 1] = data[i + 1]; - buf[j + 2] = data[i + 2]; - } - } else if (components === 1) { - for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { - buf[j] = data[i]; - } - } - resolve({ - data: buf, - width, - height - }); - }; - img.onerror = function () { - reject(new Error('JpegDecode failed to load image')); - }; - img.src = imageUrl; + (0, _util.assert)((0, _util.isArrayBuffer)(value)); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(reason => { + sink.error(reason); }); - }, this); - messageHandler.on('FetchBuiltInCMap', function (data) { - if (this.destroyed) { - return Promise.reject(new Error('Worker was destroyed')); + }; + sink.onCancel = reason => { + this._fullReader.cancel(reason); + }; + }, this); + messageHandler.on('ReaderHeadersReady', function (data) { + const headersCapability = (0, _util.createPromiseCapability)(); + const fullReader = this._fullReader; + fullReader.headersReady.then(() => { + if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { + if (this._lastProgress) { + if (loadingTask.onProgress) { + loadingTask.onProgress(this._lastProgress); + } + } + fullReader.onProgress = evt => { + if (loadingTask.onProgress) { + loadingTask.onProgress({ + loaded: evt.loaded, + total: evt.total + }); + } + }; } - return this.CMapReaderFactory.fetch({ name: data.name }); - }, this); - }, - _onUnsupportedFeature({ featureId }) { + headersCapability.resolve({ + isStreamingSupported: fullReader.isStreamingSupported, + isRangeSupported: fullReader.isRangeSupported, + contentLength: fullReader.contentLength + }); + }, headersCapability.reject); + return headersCapability.promise; + }, this); + messageHandler.on('GetRangeReader', function (data, sink) { + (0, _util.assert)(this._networkStream); + const rangeReader = this._networkStream.getRangeReader(data.begin, data.end); + sink.onPull = () => { + rangeReader.read().then(function ({ value, done }) { + if (done) { + sink.close(); + return; + } + (0, _util.assert)((0, _util.isArrayBuffer)(value)); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(reason => { + sink.error(reason); + }); + }; + sink.onCancel = reason => { + rangeReader.cancel(reason); + }; + }, this); + messageHandler.on('GetDoc', function ({ pdfInfo }) { + this.numPages = pdfInfo.numPages; + this.pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); + loadingTask._capability.resolve(this.pdfDocument); + }, this); + messageHandler.on('PasswordRequest', function (exception) { + this._passwordCapability = (0, _util.createPromiseCapability)(); + if (loadingTask.onPassword) { + const updatePassword = password => { + this._passwordCapability.resolve({ password }); + }; + try { + loadingTask.onPassword(updatePassword, exception.code); + } catch (ex) { + this._passwordCapability.reject(ex); + } + } else { + this._passwordCapability.reject(new _util.PasswordException(exception.message, exception.code)); + } + return this._passwordCapability.promise; + }, this); + messageHandler.on('PasswordException', function (exception) { + loadingTask._capability.reject(new _util.PasswordException(exception.message, exception.code)); + }, this); + messageHandler.on('InvalidPDF', function (exception) { + loadingTask._capability.reject(new _util.InvalidPDFException(exception.message)); + }, this); + messageHandler.on('MissingPDF', function (exception) { + loadingTask._capability.reject(new _util.MissingPDFException(exception.message)); + }, this); + messageHandler.on('UnexpectedResponse', function (exception) { + loadingTask._capability.reject(new _util.UnexpectedResponseException(exception.message, exception.status)); + }, this); + messageHandler.on('UnknownError', function (exception) { + loadingTask._capability.reject(new _util.UnknownErrorException(exception.message, exception.details)); + }, this); + messageHandler.on('DataLoaded', function (data) { + this.downloadInfoCapability.resolve(data); + }, this); + messageHandler.on('StartRenderPage', function (data) { if (this.destroyed) { return; } - let loadingTask = this.loadingTask; - if (loadingTask.onUnsupportedFeature) { - loadingTask.onUnsupportedFeature(featureId); + const page = this.pageCache[data.pageIndex]; + page._stats.timeEnd('Page Request'); + page._startRenderPage(data.transparency, data.intent); + }, this); + messageHandler.on('RenderPageChunk', function (data) { + if (this.destroyed) { + return; } - }, - getData: function WorkerTransport_getData() { - return this.messageHandler.sendWithPromise('GetData', null); - }, - getPage(pageNumber) { - if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) { - return Promise.reject(new Error('Invalid page request')); + const page = this.pageCache[data.pageIndex]; + page._renderPageChunk(data.operatorList, data.intent); + }, this); + messageHandler.on('commonobj', function (data) { + if (this.destroyed) { + return; } - var pageIndex = pageNumber - 1; - if (pageIndex in this.pagePromises) { - return this.pagePromises[pageIndex]; + const [id, type, exportedData] = data; + if (this.commonObjs.hasData(id)) { + return; } - var promise = this.messageHandler.sendWithPromise('GetPage', { pageIndex }).then(pageInfo => { - if (this.destroyed) { - throw new Error('Transport destroyed'); - } - let page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.pdfBug); - this.pageCache[pageIndex] = page; - return page; - }); - this.pagePromises[pageIndex] = promise; - return promise; - }, - getPageIndex: function WorkerTransport_getPageIndexByRef(ref) { - return this.messageHandler.sendWithPromise('GetPageIndex', { ref }).catch(function (reason) { - return Promise.reject(new Error(reason)); - }); - }, - getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) { - return this.messageHandler.sendWithPromise('GetAnnotations', { - pageIndex, - intent - }); - }, - getDestinations: function WorkerTransport_getDestinations() { - return this.messageHandler.sendWithPromise('GetDestinations', null); - }, - getDestination: function WorkerTransport_getDestination(id) { - if (typeof id !== 'string') { - return Promise.reject(new Error('Invalid destination request.')); - } - return this.messageHandler.sendWithPromise('GetDestination', { id }); - }, - getPageLabels: function WorkerTransport_getPageLabels() { - return this.messageHandler.sendWithPromise('GetPageLabels', null); - }, - getPageMode() { - return this.messageHandler.sendWithPromise('GetPageMode', null); - }, - getAttachments: function WorkerTransport_getAttachments() { - return this.messageHandler.sendWithPromise('GetAttachments', null); - }, - getJavaScript: function WorkerTransport_getJavaScript() { - return this.messageHandler.sendWithPromise('GetJavaScript', null); - }, - getOutline: function WorkerTransport_getOutline() { - return this.messageHandler.sendWithPromise('GetOutline', null); - }, - getMetadata: function WorkerTransport_getMetadata() { - return this.messageHandler.sendWithPromise('GetMetadata', null).then(results => { - return { - info: results[0], - metadata: results[1] ? new _metadata.Metadata(results[1]) : null, - contentDispositionFilename: this._fullReader ? this._fullReader.filename : null - }; - }); - }, - getStats: function WorkerTransport_getStats() { - return this.messageHandler.sendWithPromise('GetStats', null); - }, - startCleanup: function WorkerTransport_startCleanup() { - this.messageHandler.sendWithPromise('Cleanup', null).then(() => { - for (var i = 0, ii = this.pageCache.length; i < ii; i++) { - var page = this.pageCache[i]; - if (page) { - page.cleanup(); + switch (type) { + case 'Font': + const params = this._params; + if ('error' in exportedData) { + const exportedError = exportedData.error; + (0, _util.warn)(`Error during font loading: ${exportedError}`); + this.commonObjs.resolve(id, exportedError); + break; } + let fontRegistry = null; + if (params.pdfBug && _global_scope2.default.FontInspector && _global_scope2.default.FontInspector.enabled) { + fontRegistry = { + registerFont(font, url) { + _global_scope2.default['FontInspector'].fontAdded(font, url); + } + }; + } + const font = new _font_loader.FontFaceObject(exportedData, { + isEvalSupported: params.isEvalSupported, + disableFontFace: params.disableFontFace, + ignoreErrors: params.ignoreErrors, + onUnsupportedFeature: this._onUnsupportedFeature.bind(this), + fontRegistry + }); + const fontReady = fontObjs => { + this.commonObjs.resolve(id, font); + }; + this.fontLoader.bind([font], fontReady); + break; + case 'FontPath': + this.commonObjs.resolve(id, exportedData); + break; + default: + throw new Error(`Got unknown common object type ${type}`); + } + }, this); + messageHandler.on('obj', function (data) { + if (this.destroyed) { + return; + } + const [id, pageIndex, type, imageData] = data; + const pageProxy = this.pageCache[pageIndex]; + if (pageProxy.objs.hasData(id)) { + return; + } + switch (type) { + case 'JpegStream': + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = function () { + resolve(img); + }; + img.onerror = function () { + reject(new Error('Error during JPEG image loading')); + }; + img.src = imageData; + }).then(img => { + pageProxy.objs.resolve(id, img); + }); + case 'Image': + pageProxy.objs.resolve(id, imageData); + const MAX_IMAGE_SIZE_TO_STORE = 8000000; + if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { + pageProxy.cleanupAfterRender = true; + } + break; + default: + throw new Error(`Got unknown object type ${type}`); + } + }, this); + messageHandler.on('DocProgress', function (data) { + if (this.destroyed) { + return; + } + if (loadingTask.onProgress) { + loadingTask.onProgress({ + loaded: data.loaded, + total: data.total + }); + } + }, this); + messageHandler.on('PageError', function (data) { + if (this.destroyed) { + return; + } + const page = this.pageCache[data.pageNum - 1]; + const intentState = page.intentStates[data.intent]; + if (intentState.displayReadyCapability) { + intentState.displayReadyCapability.reject(data.error); + } else { + throw new Error(data.error); + } + if (intentState.operatorList) { + intentState.operatorList.lastChunk = true; + for (let i = 0; i < intentState.renderTasks.length; i++) { + intentState.renderTasks[i].operatorListChanged(); } - this.commonObjs.clear(); - this.fontLoader.clear(); - }); - }, - get loadingParams() { - let params = this._params; - return (0, _util.shadow)(this, 'loadingParams', { - disableAutoFetch: params.disableAutoFetch, - disableCreateObjectURL: params.disableCreateObjectURL, - disableFontFace: params.disableFontFace, - nativeImageDecoderSupport: params.nativeImageDecoderSupport + } + }, this); + messageHandler.on('UnsupportedFeature', this._onUnsupportedFeature, this); + messageHandler.on('JpegDecode', function (data) { + if (this.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + if (typeof document === 'undefined') { + return Promise.reject(new Error('"document" is not defined.')); + } + const [imageUrl, components] = data; + if (components !== 3 && components !== 1) { + return Promise.reject(new Error('Only 3 components or 1 component can be returned')); + } + return new Promise(function (resolve, reject) { + const img = new Image(); + img.onload = function () { + const width = img.width; + const height = img.height; + const size = width * height; + const rgbaLength = size * 4; + const buf = new Uint8ClampedArray(size * components); + const tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = width; + tmpCanvas.height = height; + const tmpCtx = tmpCanvas.getContext('2d'); + tmpCtx.drawImage(img, 0, 0); + const data = tmpCtx.getImageData(0, 0, width, height).data; + if (components === 3) { + for (let i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { + buf[j] = data[i]; + buf[j + 1] = data[i + 1]; + buf[j + 2] = data[i + 2]; + } + } else if (components === 1) { + for (let i = 0, j = 0; i < rgbaLength; i += 4, j++) { + buf[j] = data[i]; + } + } + resolve({ + data: buf, + width, + height + }); + }; + img.onerror = function () { + reject(new Error('JpegDecode failed to load image')); + }; + img.src = imageUrl; }); + }, this); + messageHandler.on('FetchBuiltInCMap', function (data) { + if (this.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + return this.CMapReaderFactory.fetch({ name: data.name }); + }, this); + } + _onUnsupportedFeature({ featureId }) { + if (this.destroyed) { + return; } - }; - return WorkerTransport; -}(); + if (this.loadingTask.onUnsupportedFeature) { + this.loadingTask.onUnsupportedFeature(featureId); + } + } + getData() { + return this.messageHandler.sendWithPromise('GetData', null); + } + getPage(pageNumber) { + if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) { + return Promise.reject(new Error('Invalid page request')); + } + const pageIndex = pageNumber - 1; + if (pageIndex in this.pagePromises) { + return this.pagePromises[pageIndex]; + } + const promise = this.messageHandler.sendWithPromise('GetPage', { pageIndex }).then(pageInfo => { + if (this.destroyed) { + throw new Error('Transport destroyed'); + } + const page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.pdfBug); + this.pageCache[pageIndex] = page; + return page; + }); + this.pagePromises[pageIndex] = promise; + return promise; + } + getPageIndex(ref) { + return this.messageHandler.sendWithPromise('GetPageIndex', { ref }).catch(function (reason) { + return Promise.reject(new Error(reason)); + }); + } + getAnnotations(pageIndex, intent) { + return this.messageHandler.sendWithPromise('GetAnnotations', { + pageIndex, + intent + }); + } + getDestinations() { + return this.messageHandler.sendWithPromise('GetDestinations', null); + } + getDestination(id) { + if (typeof id !== 'string') { + return Promise.reject(new Error('Invalid destination request.')); + } + return this.messageHandler.sendWithPromise('GetDestination', { id }); + } + getPageLabels() { + return this.messageHandler.sendWithPromise('GetPageLabels', null); + } + getPageMode() { + return this.messageHandler.sendWithPromise('GetPageMode', null); + } + getAttachments() { + return this.messageHandler.sendWithPromise('GetAttachments', null); + } + getJavaScript() { + return this.messageHandler.sendWithPromise('GetJavaScript', null); + } + getOutline() { + return this.messageHandler.sendWithPromise('GetOutline', null); + } + getPermissions() { + return this.messageHandler.sendWithPromise('GetPermissions', null); + } + getMetadata() { + return this.messageHandler.sendWithPromise('GetMetadata', null).then(results => { + return { + info: results[0], + metadata: results[1] ? new _metadata.Metadata(results[1]) : null, + contentDispositionFilename: this._fullReader ? this._fullReader.filename : null + }; + }); + } + getStats() { + return this.messageHandler.sendWithPromise('GetStats', null); + } + startCleanup() { + this.messageHandler.sendWithPromise('Cleanup', null).then(() => { + for (let i = 0, ii = this.pageCache.length; i < ii; i++) { + const page = this.pageCache[i]; + if (page) { + page.cleanup(); + } + } + this.commonObjs.clear(); + this.fontLoader.clear(); + }); + } + get loadingParams() { + const params = this._params; + return (0, _util.shadow)(this, 'loadingParams', { + disableAutoFetch: params.disableAutoFetch, + disableCreateObjectURL: params.disableCreateObjectURL, + disableFontFace: params.disableFontFace, + nativeImageDecoderSupport: params.nativeImageDecoderSupport + }); + } +} var PDFObjects = function PDFObjectsClosure() { function PDFObjects() { this.objs = Object.create(null); @@ -5558,8 +5553,8 @@ var InternalRenderTask = function InternalRenderTaskClosure() { }(); var version, build; { - exports.version = version = '2.0.775'; - exports.build = build = '20cd1b35'; + exports.version = version = '2.0.813'; + exports.build = build = 'af89ec27'; } exports.getDocument = getDocument; exports.LoopbackPort = LoopbackPort; diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index b8981a25164b..6267009d258f 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2017 Mozilla Foundation + * Copyright 2018 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -var pdfjsVersion = '2.0.775'; -var pdfjsBuild = '20cd1b35'; +var pdfjsVersion = '2.0.813'; +var pdfjsBuild = 'af89ec27'; var pdfjsCoreWorker = __w_pdfjs_require__(1); exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler; @@ -327,7 +327,7 @@ var WorkerMessageHandler = { var cancelXHRs = null; var WorkerTasks = []; let apiVersion = docParams.apiVersion; - let workerVersion = '2.0.775'; + let workerVersion = '2.0.813'; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); } @@ -569,6 +569,9 @@ var WorkerMessageHandler = { handler.on('GetOutline', function wphSetupGetOutline(data) { return pdfManager.ensureCatalog('documentOutline'); }); + handler.on('GetPermissions', function (data) { + return pdfManager.ensureCatalog('permissions'); + }); handler.on('GetMetadata', function wphSetupGetMetadata(data) { return Promise.all([pdfManager.ensureDoc('documentInfo'), pdfManager.ensureCatalog('metadata')]); }); @@ -715,7 +718,7 @@ exports.WorkerMessageHandler = WorkerMessageHandler; Object.defineProperty(exports, "__esModule", { value: true }); -exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; +exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; __w_pdfjs_require__(3); @@ -729,6 +732,16 @@ const NativeImageDecoding = { DECODE: 'decode', DISPLAY: 'display' }; +const PermissionFlag = { + PRINT: 0x04, + MODIFY_CONTENTS: 0x08, + COPY: 0x10, + MODIFY_ANNOTATIONS: 0x20, + FILL_INTERACTIVE_FORMS: 0x100, + COPY_FOR_ACCESSIBILITY: 0x200, + ASSEMBLE: 0x400, + PRINT_HIGH_QUALITY: 0x800 +}; var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -1451,6 +1464,7 @@ exports.MissingPDFException = MissingPDFException; exports.NativeImageDecoding = NativeImageDecoding; exports.PasswordException = PasswordException; exports.PasswordResponses = PasswordResponses; +exports.PermissionFlag = PermissionFlag; exports.StreamType = StreamType; exports.TextRenderingMode = TextRenderingMode; exports.UnexpectedResponseException = UnexpectedResponseException; @@ -5745,519 +5759,540 @@ var _colorspace = __w_pdfjs_require__(25); function fetchDestination(dest) { return (0, _primitives.isDict)(dest) ? dest.get('D') : dest; } -var Catalog = function CatalogClosure() { - function Catalog(pdfManager, xref) { +class Catalog { + constructor(pdfManager, xref) { this.pdfManager = pdfManager; this.xref = xref; this.catDict = xref.getCatalogObj(); if (!(0, _primitives.isDict)(this.catDict)) { - throw new _util.FormatError('catalog object is not a dictionary'); + throw new _util.FormatError('Catalog object is not a dictionary.'); } this.fontCache = new _primitives.RefSetCache(); this.builtInCMapCache = new Map(); this.pageKidsCountCache = new _primitives.RefSetCache(); } - Catalog.prototype = { - get metadata() { - var streamRef = this.catDict.getRaw('Metadata'); - if (!(0, _primitives.isRef)(streamRef)) { - return (0, _util.shadow)(this, 'metadata', null); - } - var encryptMetadata = !this.xref.encrypt ? false : this.xref.encrypt.encryptMetadata; - var stream = this.xref.fetch(streamRef, !encryptMetadata); - var metadata; - if (stream && (0, _primitives.isDict)(stream.dict)) { - var type = stream.dict.get('Type'); - var subtype = stream.dict.get('Subtype'); - if ((0, _primitives.isName)(type, 'Metadata') && (0, _primitives.isName)(subtype, 'XML')) { - try { - metadata = (0, _util.stringToUTF8String)((0, _util.bytesToString)(stream.getBytes())); - } catch (e) { - if (e instanceof _util.MissingDataException) { - throw e; - } - (0, _util.info)('Skipping invalid metadata.'); - } - } - } - return (0, _util.shadow)(this, 'metadata', metadata); - }, - get toplevelPagesDict() { - var pagesObj = this.catDict.get('Pages'); - if (!(0, _primitives.isDict)(pagesObj)) { - throw new _util.FormatError('invalid top-level pages dictionary'); - } - return (0, _util.shadow)(this, 'toplevelPagesDict', pagesObj); - }, - get documentOutline() { - var obj = null; - try { - obj = this.readDocumentOutline(); - } catch (ex) { - if (ex instanceof _util.MissingDataException) { - throw ex; - } - (0, _util.warn)('Unable to read document outline'); - } - return (0, _util.shadow)(this, 'documentOutline', obj); - }, - readDocumentOutline: function Catalog_readDocumentOutline() { - var obj = this.catDict.get('Outlines'); - if (!(0, _primitives.isDict)(obj)) { - return null; - } - obj = obj.getRaw('First'); - if (!(0, _primitives.isRef)(obj)) { - return null; - } - var root = { items: [] }; - var queue = [{ - obj, - parent: root - }]; - var processed = new _primitives.RefSet(); - processed.put(obj); - var xref = this.xref, - blackColor = new Uint8ClampedArray(3); - while (queue.length > 0) { - var i = queue.shift(); - var outlineDict = xref.fetchIfRef(i.obj); - if (outlineDict === null) { - continue; - } - if (!outlineDict.has('Title')) { - throw new _util.FormatError('Invalid outline item'); - } - var data = { - url: null, - dest: null - }; - Catalog.parseDestDictionary({ - destDict: outlineDict, - resultObj: data, - docBaseUrl: this.pdfManager.docBaseUrl - }); - var title = outlineDict.get('Title'); - var flags = outlineDict.get('F') || 0; - var color = outlineDict.getArray('C'), - rgbColor = blackColor; - if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { - rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); - } - var outlineItem = { - dest: data.dest, - url: data.url, - unsafeUrl: data.unsafeUrl, - newWindow: data.newWindow, - title: (0, _util.stringToPDFString)(title), - color: rgbColor, - count: outlineDict.get('Count'), - bold: !!(flags & 2), - italic: !!(flags & 1), - items: [] - }; - i.parent.items.push(outlineItem); - obj = outlineDict.getRaw('First'); - if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { - queue.push({ - obj, - parent: outlineItem - }); - processed.put(obj); - } - obj = outlineDict.getRaw('Next'); - if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { - queue.push({ - obj, - parent: i.parent - }); - processed.put(obj); - } - } - return root.items.length > 0 ? root.items : null; - }, - get numPages() { - var obj = this.toplevelPagesDict.get('Count'); - if (!Number.isInteger(obj)) { - throw new _util.FormatError('page count in top level pages object is not an integer'); - } - return (0, _util.shadow)(this, 'numPages', obj); - }, - get destinations() { - const obj = this._readDests(), - dests = Object.create(null); - if (obj instanceof NameTree) { - const names = obj.getAll(); - for (let name in names) { - dests[name] = fetchDestination(names[name]); - } - } else if (obj instanceof _primitives.Dict) { - obj.forEach(function (key, value) { - if (value) { - dests[key] = fetchDestination(value); - } - }); - } - return (0, _util.shadow)(this, 'destinations', dests); - }, - getDestination(destinationId) { - const obj = this._readDests(); - if (obj instanceof NameTree || obj instanceof _primitives.Dict) { - return fetchDestination(obj.get(destinationId) || null); - } - return null; - }, - _readDests() { - const obj = this.catDict.get('Names'); - if (obj && obj.has('Dests')) { - return new NameTree(obj.getRaw('Dests'), this.xref); - } else if (this.catDict.has('Dests')) { - return this.catDict.get('Dests'); - } - }, - get pageLabels() { - var obj = null; - try { - obj = this.readPageLabels(); - } catch (ex) { - if (ex instanceof _util.MissingDataException) { - throw ex; - } - (0, _util.warn)('Unable to read page labels.'); - } - return (0, _util.shadow)(this, 'pageLabels', obj); - }, - readPageLabels: function Catalog_readPageLabels() { - var obj = this.catDict.getRaw('PageLabels'); - if (!obj) { - return null; - } - var pageLabels = new Array(this.numPages); - var style = null; - var prefix = ''; - var numberTree = new NumberTree(obj, this.xref); - var nums = numberTree.getAll(); - var currentLabel = '', - currentIndex = 1; - for (var i = 0, ii = this.numPages; i < ii; i++) { - if (i in nums) { - const labelDict = nums[i]; - if (!(0, _primitives.isDict)(labelDict)) { - throw new _util.FormatError('The PageLabel is not a dictionary.'); - } - if (labelDict.has('Type') && !(0, _primitives.isName)(labelDict.get('Type'), 'PageLabel')) { - throw new _util.FormatError('Invalid type in PageLabel dictionary.'); - } - if (labelDict.has('S')) { - const s = labelDict.get('S'); - if (!(0, _primitives.isName)(s)) { - throw new _util.FormatError('Invalid style in PageLabel dictionary.'); - } - style = s.name; - } else { - style = null; - } - if (labelDict.has('P')) { - const p = labelDict.get('P'); - if (!(0, _util.isString)(p)) { - throw new _util.FormatError('Invalid prefix in PageLabel dictionary.'); - } - prefix = (0, _util.stringToPDFString)(p); - } else { - prefix = ''; - } - if (labelDict.has('St')) { - const st = labelDict.get('St'); - if (!(Number.isInteger(st) && st >= 1)) { - throw new _util.FormatError('Invalid start in PageLabel dictionary.'); - } - currentIndex = st; - } else { - currentIndex = 1; - } - } - switch (style) { - case 'D': - currentLabel = currentIndex; - break; - case 'R': - case 'r': - currentLabel = (0, _util.toRomanNumerals)(currentIndex, style === 'r'); - break; - case 'A': - case 'a': - var LIMIT = 26; - var A_UPPER_CASE = 0x41, - A_LOWER_CASE = 0x61; - var baseCharCode = style === 'a' ? A_LOWER_CASE : A_UPPER_CASE; - var letterIndex = currentIndex - 1; - var character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); - var charBuf = []; - for (var j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) { - charBuf.push(character); - } - currentLabel = charBuf.join(''); - break; - default: - if (style) { - throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`); - } - currentLabel = ''; - } - pageLabels[i] = prefix + currentLabel; - currentIndex++; - } - return pageLabels; - }, - get pageMode() { - let obj = this.catDict.get('PageMode'); - let pageMode = 'UseNone'; - if ((0, _primitives.isName)(obj)) { - switch (obj.name) { - case 'UseNone': - case 'UseOutlines': - case 'UseThumbs': - case 'FullScreen': - case 'UseOC': - case 'UseAttachments': - pageMode = obj.name; - } - } - return (0, _util.shadow)(this, 'pageMode', pageMode); - }, - get attachments() { - var xref = this.xref; - var attachments = null, - nameTreeRef; - var obj = this.catDict.get('Names'); - if (obj) { - nameTreeRef = obj.getRaw('EmbeddedFiles'); - } - if (nameTreeRef) { - var nameTree = new NameTree(nameTreeRef, xref); - var names = nameTree.getAll(); - for (var name in names) { - var fs = new FileSpec(names[name], xref); - if (!attachments) { - attachments = Object.create(null); - } - attachments[(0, _util.stringToPDFString)(name)] = fs.serializable; - } - } - return (0, _util.shadow)(this, 'attachments', attachments); - }, - get javaScript() { - var xref = this.xref; - var obj = this.catDict.get('Names'); - let javaScript = null; - function appendIfJavaScriptDict(jsDict) { - var type = jsDict.get('S'); - if (!(0, _primitives.isName)(type, 'JavaScript')) { - return; - } - var js = jsDict.get('JS'); - if ((0, _primitives.isStream)(js)) { - js = (0, _util.bytesToString)(js.getBytes()); - } else if (!(0, _util.isString)(js)) { - return; - } - if (!javaScript) { - javaScript = []; - } - javaScript.push((0, _util.stringToPDFString)(js)); - } - if (obj && obj.has('JavaScript')) { - var nameTree = new NameTree(obj.getRaw('JavaScript'), xref); - var names = nameTree.getAll(); - for (var name in names) { - var jsDict = names[name]; - if ((0, _primitives.isDict)(jsDict)) { - appendIfJavaScriptDict(jsDict); - } - } - } - var openactionDict = this.catDict.get('OpenAction'); - if ((0, _primitives.isDict)(openactionDict, 'Action')) { - var actionType = openactionDict.get('S'); - if ((0, _primitives.isName)(actionType, 'Named')) { - var action = openactionDict.get('N'); - if ((0, _primitives.isName)(action, 'Print')) { - if (!javaScript) { - javaScript = []; - } - javaScript.push('print({});'); - } - } else { - appendIfJavaScriptDict(openactionDict); - } - } - return (0, _util.shadow)(this, 'javaScript', javaScript); - }, - cleanup: function Catalog_cleanup() { - this.pageKidsCountCache.clear(); - var promises = []; - this.fontCache.forEach(function (promise) { - promises.push(promise); - }); - return Promise.all(promises).then(translatedFonts => { - for (var i = 0, ii = translatedFonts.length; i < ii; i++) { - var font = translatedFonts[i].dict; - delete font.translated; - } - this.fontCache.clear(); - this.builtInCMapCache.clear(); - }); - }, - getPageDict: function Catalog_getPageDict(pageIndex) { - var capability = (0, _util.createPromiseCapability)(); - var nodesToVisit = [this.catDict.getRaw('Pages')]; - var count, - currentPageIndex = 0; - var xref = this.xref, - pageKidsCountCache = this.pageKidsCountCache; - function next() { - while (nodesToVisit.length) { - var currentNode = nodesToVisit.pop(); - if ((0, _primitives.isRef)(currentNode)) { - count = pageKidsCountCache.get(currentNode); - if (count > 0 && currentPageIndex + count < pageIndex) { - currentPageIndex += count; - continue; - } - xref.fetchAsync(currentNode).then(function (obj) { - if ((0, _primitives.isDict)(obj, 'Page') || (0, _primitives.isDict)(obj) && !obj.has('Kids')) { - if (pageIndex === currentPageIndex) { - if (currentNode && !pageKidsCountCache.has(currentNode)) { - pageKidsCountCache.put(currentNode, 1); - } - capability.resolve([obj, currentNode]); - } else { - currentPageIndex++; - next(); - } - return; - } - nodesToVisit.push(obj); - next(); - }, capability.reject); - return; - } - if (!(0, _primitives.isDict)(currentNode)) { - capability.reject(new _util.FormatError('page dictionary kid reference points to wrong type of object')); - return; - } - count = currentNode.get('Count'); - if (Number.isInteger(count) && count >= 0) { - var objId = currentNode.objId; - if (objId && !pageKidsCountCache.has(objId)) { - pageKidsCountCache.put(objId, count); - } - if (currentPageIndex + count <= pageIndex) { - currentPageIndex += count; - continue; - } - } - var kids = currentNode.get('Kids'); - if (!Array.isArray(kids)) { - if ((0, _primitives.isName)(currentNode.get('Type'), 'Page') || !currentNode.has('Type') && currentNode.has('Contents')) { - if (currentPageIndex === pageIndex) { - capability.resolve([currentNode, null]); - return; - } - currentPageIndex++; - continue; - } - capability.reject(new _util.FormatError('page dictionary kids object is not an array')); - return; - } - for (var last = kids.length - 1; last >= 0; last--) { - nodesToVisit.push(kids[last]); - } - } - capability.reject(new Error('Page index ' + pageIndex + ' not found.')); - } - next(); - return capability.promise; - }, - getPageIndex: function Catalog_getPageIndex(pageRef) { - var xref = this.xref; - function pagesBeforeRef(kidRef) { - var total = 0; - var parentRef; - return xref.fetchAsync(kidRef).then(function (node) { - if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, 'Page') && !((0, _primitives.isDict)(node) && !node.has('Type') && node.has('Contents'))) { - throw new _util.FormatError('The reference does not point to a /Page Dict.'); - } - if (!node) { - return null; - } - if (!(0, _primitives.isDict)(node)) { - throw new _util.FormatError('node must be a Dict.'); - } - parentRef = node.getRaw('Parent'); - return node.getAsync('Parent'); - }).then(function (parent) { - if (!parent) { - return null; - } - if (!(0, _primitives.isDict)(parent)) { - throw new _util.FormatError('parent must be a Dict.'); - } - return parent.getAsync('Kids'); - }).then(function (kids) { - if (!kids) { - return null; - } - var kidPromises = []; - var found = false; - for (var i = 0; i < kids.length; i++) { - var kid = kids[i]; - if (!(0, _primitives.isRef)(kid)) { - throw new _util.FormatError('kid must be a Ref.'); - } - if ((0, _primitives.isRefsEqual)(kid, kidRef)) { - found = true; - break; - } - kidPromises.push(xref.fetchAsync(kid).then(function (kid) { - if (!(0, _primitives.isDict)(kid)) { - throw new _util.FormatError('kid node must be a Dict.'); - } - if (kid.has('Count')) { - var count = kid.get('Count'); - total += count; - } else { - total++; - } - })); - } - if (!found) { - throw new _util.FormatError('kid ref not found in parents kids'); - } - return Promise.all(kidPromises).then(function () { - return [total, parentRef]; - }); - }); - } - var total = 0; - function next(ref) { - return pagesBeforeRef(ref).then(function (args) { - if (!args) { - return total; - } - var count = args[0]; - var parentRef = args[1]; - total += count; - return next(parentRef); - }); - } - return next(pageRef); + get metadata() { + const streamRef = this.catDict.getRaw('Metadata'); + if (!(0, _primitives.isRef)(streamRef)) { + return (0, _util.shadow)(this, 'metadata', null); } - }; - Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) { + const suppressEncryption = !(this.xref.encrypt && this.xref.encrypt.encryptMetadata); + const stream = this.xref.fetch(streamRef, suppressEncryption); + let metadata; + if (stream && (0, _primitives.isDict)(stream.dict)) { + const type = stream.dict.get('Type'); + const subtype = stream.dict.get('Subtype'); + if ((0, _primitives.isName)(type, 'Metadata') && (0, _primitives.isName)(subtype, 'XML')) { + try { + metadata = (0, _util.stringToUTF8String)((0, _util.bytesToString)(stream.getBytes())); + } catch (e) { + if (e instanceof _util.MissingDataException) { + throw e; + } + (0, _util.info)('Skipping invalid metadata.'); + } + } + } + return (0, _util.shadow)(this, 'metadata', metadata); + } + get toplevelPagesDict() { + const pagesObj = this.catDict.get('Pages'); + if (!(0, _primitives.isDict)(pagesObj)) { + throw new _util.FormatError('Invalid top-level pages dictionary.'); + } + return (0, _util.shadow)(this, 'toplevelPagesDict', pagesObj); + } + get documentOutline() { + let obj = null; + try { + obj = this._readDocumentOutline(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read document outline.'); + } + return (0, _util.shadow)(this, 'documentOutline', obj); + } + _readDocumentOutline() { + let obj = this.catDict.get('Outlines'); + if (!(0, _primitives.isDict)(obj)) { + return null; + } + obj = obj.getRaw('First'); + if (!(0, _primitives.isRef)(obj)) { + return null; + } + const root = { items: [] }; + const queue = [{ + obj, + parent: root + }]; + const processed = new _primitives.RefSet(); + processed.put(obj); + const xref = this.xref, + blackColor = new Uint8ClampedArray(3); + while (queue.length > 0) { + const i = queue.shift(); + const outlineDict = xref.fetchIfRef(i.obj); + if (outlineDict === null) { + continue; + } + if (!outlineDict.has('Title')) { + throw new _util.FormatError('Invalid outline item encountered.'); + } + const data = { + url: null, + dest: null + }; + Catalog.parseDestDictionary({ + destDict: outlineDict, + resultObj: data, + docBaseUrl: this.pdfManager.docBaseUrl + }); + const title = outlineDict.get('Title'); + const flags = outlineDict.get('F') || 0; + const color = outlineDict.getArray('C'); + let rgbColor = blackColor; + if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { + rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); + } + const outlineItem = { + dest: data.dest, + url: data.url, + unsafeUrl: data.unsafeUrl, + newWindow: data.newWindow, + title: (0, _util.stringToPDFString)(title), + color: rgbColor, + count: outlineDict.get('Count'), + bold: !!(flags & 2), + italic: !!(flags & 1), + items: [] + }; + i.parent.items.push(outlineItem); + obj = outlineDict.getRaw('First'); + if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { + queue.push({ + obj, + parent: outlineItem + }); + processed.put(obj); + } + obj = outlineDict.getRaw('Next'); + if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { + queue.push({ + obj, + parent: i.parent + }); + processed.put(obj); + } + } + return root.items.length > 0 ? root.items : null; + } + get permissions() { + let permissions = null; + try { + permissions = this._readPermissions(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read permissions.'); + } + return (0, _util.shadow)(this, 'permissions', permissions); + } + _readPermissions() { + const encrypt = this.xref.trailer.get('Encrypt'); + if (!(0, _primitives.isDict)(encrypt)) { + return null; + } + let flags = encrypt.get('P'); + if (!(0, _util.isNum)(flags)) { + return null; + } + flags += 2 ** 32; + const permissions = []; + for (const key in _util.PermissionFlag) { + const value = _util.PermissionFlag[key]; + if (flags & value) { + permissions.push(value); + } + } + return permissions; + } + get numPages() { + const obj = this.toplevelPagesDict.get('Count'); + if (!Number.isInteger(obj)) { + throw new _util.FormatError('Page count in top-level pages dictionary is not an integer.'); + } + return (0, _util.shadow)(this, 'numPages', obj); + } + get destinations() { + const obj = this._readDests(), + dests = Object.create(null); + if (obj instanceof NameTree) { + const names = obj.getAll(); + for (let name in names) { + dests[name] = fetchDestination(names[name]); + } + } else if (obj instanceof _primitives.Dict) { + obj.forEach(function (key, value) { + if (value) { + dests[key] = fetchDestination(value); + } + }); + } + return (0, _util.shadow)(this, 'destinations', dests); + } + getDestination(destinationId) { + const obj = this._readDests(); + if (obj instanceof NameTree || obj instanceof _primitives.Dict) { + return fetchDestination(obj.get(destinationId) || null); + } + return null; + } + _readDests() { + const obj = this.catDict.get('Names'); + if (obj && obj.has('Dests')) { + return new NameTree(obj.getRaw('Dests'), this.xref); + } else if (this.catDict.has('Dests')) { + return this.catDict.get('Dests'); + } + } + get pageLabels() { + let obj = null; + try { + obj = this._readPageLabels(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read page labels.'); + } + return (0, _util.shadow)(this, 'pageLabels', obj); + } + _readPageLabels() { + const obj = this.catDict.getRaw('PageLabels'); + if (!obj) { + return null; + } + const pageLabels = new Array(this.numPages); + let style = null, + prefix = ''; + const numberTree = new NumberTree(obj, this.xref); + const nums = numberTree.getAll(); + let currentLabel = '', + currentIndex = 1; + for (let i = 0, ii = this.numPages; i < ii; i++) { + if (i in nums) { + const labelDict = nums[i]; + if (!(0, _primitives.isDict)(labelDict)) { + throw new _util.FormatError('PageLabel is not a dictionary.'); + } + if (labelDict.has('Type') && !(0, _primitives.isName)(labelDict.get('Type'), 'PageLabel')) { + throw new _util.FormatError('Invalid type in PageLabel dictionary.'); + } + if (labelDict.has('S')) { + const s = labelDict.get('S'); + if (!(0, _primitives.isName)(s)) { + throw new _util.FormatError('Invalid style in PageLabel dictionary.'); + } + style = s.name; + } else { + style = null; + } + if (labelDict.has('P')) { + const p = labelDict.get('P'); + if (!(0, _util.isString)(p)) { + throw new _util.FormatError('Invalid prefix in PageLabel dictionary.'); + } + prefix = (0, _util.stringToPDFString)(p); + } else { + prefix = ''; + } + if (labelDict.has('St')) { + const st = labelDict.get('St'); + if (!(Number.isInteger(st) && st >= 1)) { + throw new _util.FormatError('Invalid start in PageLabel dictionary.'); + } + currentIndex = st; + } else { + currentIndex = 1; + } + } + switch (style) { + case 'D': + currentLabel = currentIndex; + break; + case 'R': + case 'r': + currentLabel = (0, _util.toRomanNumerals)(currentIndex, style === 'r'); + break; + case 'A': + case 'a': + const LIMIT = 26; + const A_UPPER_CASE = 0x41, + A_LOWER_CASE = 0x61; + const baseCharCode = style === 'a' ? A_LOWER_CASE : A_UPPER_CASE; + const letterIndex = currentIndex - 1; + const character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); + const charBuf = []; + for (let j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) { + charBuf.push(character); + } + currentLabel = charBuf.join(''); + break; + default: + if (style) { + throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`); + } + currentLabel = ''; + } + pageLabels[i] = prefix + currentLabel; + currentIndex++; + } + return pageLabels; + } + get pageMode() { + const obj = this.catDict.get('PageMode'); + let pageMode = 'UseNone'; + if ((0, _primitives.isName)(obj)) { + switch (obj.name) { + case 'UseNone': + case 'UseOutlines': + case 'UseThumbs': + case 'FullScreen': + case 'UseOC': + case 'UseAttachments': + pageMode = obj.name; + } + } + return (0, _util.shadow)(this, 'pageMode', pageMode); + } + get attachments() { + const obj = this.catDict.get('Names'); + let attachments = null; + if (obj && obj.has('EmbeddedFiles')) { + const nameTree = new NameTree(obj.getRaw('EmbeddedFiles'), this.xref); + const names = nameTree.getAll(); + for (const name in names) { + const fs = new FileSpec(names[name], this.xref); + if (!attachments) { + attachments = Object.create(null); + } + attachments[(0, _util.stringToPDFString)(name)] = fs.serializable; + } + } + return (0, _util.shadow)(this, 'attachments', attachments); + } + get javaScript() { + const obj = this.catDict.get('Names'); + let javaScript = null; + function appendIfJavaScriptDict(jsDict) { + const type = jsDict.get('S'); + if (!(0, _primitives.isName)(type, 'JavaScript')) { + return; + } + let js = jsDict.get('JS'); + if ((0, _primitives.isStream)(js)) { + js = (0, _util.bytesToString)(js.getBytes()); + } else if (!(0, _util.isString)(js)) { + return; + } + if (!javaScript) { + javaScript = []; + } + javaScript.push((0, _util.stringToPDFString)(js)); + } + if (obj && obj.has('JavaScript')) { + const nameTree = new NameTree(obj.getRaw('JavaScript'), this.xref); + const names = nameTree.getAll(); + for (const name in names) { + const jsDict = names[name]; + if ((0, _primitives.isDict)(jsDict)) { + appendIfJavaScriptDict(jsDict); + } + } + } + const openActionDict = this.catDict.get('OpenAction'); + if ((0, _primitives.isDict)(openActionDict, 'Action')) { + const actionType = openActionDict.get('S'); + if ((0, _primitives.isName)(actionType, 'Named')) { + const action = openActionDict.get('N'); + if ((0, _primitives.isName)(action, 'Print')) { + if (!javaScript) { + javaScript = []; + } + javaScript.push('print({});'); + } + } else { + appendIfJavaScriptDict(openActionDict); + } + } + return (0, _util.shadow)(this, 'javaScript', javaScript); + } + cleanup() { + this.pageKidsCountCache.clear(); + const promises = []; + this.fontCache.forEach(function (promise) { + promises.push(promise); + }); + return Promise.all(promises).then(translatedFonts => { + for (let i = 0, ii = translatedFonts.length; i < ii; i++) { + const font = translatedFonts[i].dict; + delete font.translated; + } + this.fontCache.clear(); + this.builtInCMapCache.clear(); + }); + } + getPageDict(pageIndex) { + const capability = (0, _util.createPromiseCapability)(); + const nodesToVisit = [this.catDict.getRaw('Pages')]; + const xref = this.xref, + pageKidsCountCache = this.pageKidsCountCache; + let count, + currentPageIndex = 0; + function next() { + while (nodesToVisit.length) { + const currentNode = nodesToVisit.pop(); + if ((0, _primitives.isRef)(currentNode)) { + count = pageKidsCountCache.get(currentNode); + if (count > 0 && currentPageIndex + count < pageIndex) { + currentPageIndex += count; + continue; + } + xref.fetchAsync(currentNode).then(function (obj) { + if ((0, _primitives.isDict)(obj, 'Page') || (0, _primitives.isDict)(obj) && !obj.has('Kids')) { + if (pageIndex === currentPageIndex) { + if (currentNode && !pageKidsCountCache.has(currentNode)) { + pageKidsCountCache.put(currentNode, 1); + } + capability.resolve([obj, currentNode]); + } else { + currentPageIndex++; + next(); + } + return; + } + nodesToVisit.push(obj); + next(); + }, capability.reject); + return; + } + if (!(0, _primitives.isDict)(currentNode)) { + capability.reject(new _util.FormatError('Page dictionary kid reference points to wrong type of object.')); + return; + } + count = currentNode.get('Count'); + if (Number.isInteger(count) && count >= 0) { + const objId = currentNode.objId; + if (objId && !pageKidsCountCache.has(objId)) { + pageKidsCountCache.put(objId, count); + } + if (currentPageIndex + count <= pageIndex) { + currentPageIndex += count; + continue; + } + } + const kids = currentNode.get('Kids'); + if (!Array.isArray(kids)) { + if ((0, _primitives.isName)(currentNode.get('Type'), 'Page') || !currentNode.has('Type') && currentNode.has('Contents')) { + if (currentPageIndex === pageIndex) { + capability.resolve([currentNode, null]); + return; + } + currentPageIndex++; + continue; + } + capability.reject(new _util.FormatError('Page dictionary kids object is not an array.')); + return; + } + for (let last = kids.length - 1; last >= 0; last--) { + nodesToVisit.push(kids[last]); + } + } + capability.reject(new Error(`Page index ${pageIndex} not found.`)); + } + next(); + return capability.promise; + } + getPageIndex(pageRef) { + const xref = this.xref; + function pagesBeforeRef(kidRef) { + let total = 0, + parentRef; + return xref.fetchAsync(kidRef).then(function (node) { + if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, 'Page') && !((0, _primitives.isDict)(node) && !node.has('Type') && node.has('Contents'))) { + throw new _util.FormatError('The reference does not point to a /Page dictionary.'); + } + if (!node) { + return null; + } + if (!(0, _primitives.isDict)(node)) { + throw new _util.FormatError('Node must be a dictionary.'); + } + parentRef = node.getRaw('Parent'); + return node.getAsync('Parent'); + }).then(function (parent) { + if (!parent) { + return null; + } + if (!(0, _primitives.isDict)(parent)) { + throw new _util.FormatError('Parent must be a dictionary.'); + } + return parent.getAsync('Kids'); + }).then(function (kids) { + if (!kids) { + return null; + } + const kidPromises = []; + let found = false; + for (let i = 0, ii = kids.length; i < ii; i++) { + const kid = kids[i]; + if (!(0, _primitives.isRef)(kid)) { + throw new _util.FormatError('Kid must be a reference.'); + } + if ((0, _primitives.isRefsEqual)(kid, kidRef)) { + found = true; + break; + } + kidPromises.push(xref.fetchAsync(kid).then(function (kid) { + if (!(0, _primitives.isDict)(kid)) { + throw new _util.FormatError('Kid node must be a dictionary.'); + } + if (kid.has('Count')) { + total += kid.get('Count'); + } else { + total++; + } + })); + } + if (!found) { + throw new _util.FormatError('Kid reference not found in parent\'s kids.'); + } + return Promise.all(kidPromises).then(function () { + return [total, parentRef]; + }); + }); + } + let total = 0; + function next(ref) { + return pagesBeforeRef(ref).then(function (args) { + if (!args) { + return total; + } + const [count, parentRef] = args; + total += count; + return next(parentRef); + }); + } + return next(pageRef); + } + static parseDestDictionary(params) { function addDefaultProtocolToUrl(url) { if (url.indexOf('www.') === 0) { - return 'http://' + url; + return `http://${url}`; } return url; } @@ -6268,30 +6303,30 @@ var Catalog = function CatalogClosure() { return url; } } - var destDict = params.destDict; + const destDict = params.destDict; if (!(0, _primitives.isDict)(destDict)) { - (0, _util.warn)('parseDestDictionary: "destDict" must be a dictionary.'); + (0, _util.warn)('parseDestDictionary: `destDict` must be a dictionary.'); return; } - var resultObj = params.resultObj; + const resultObj = params.resultObj; if (typeof resultObj !== 'object') { - (0, _util.warn)('parseDestDictionary: "resultObj" must be an object.'); + (0, _util.warn)('parseDestDictionary: `resultObj` must be an object.'); return; } - var docBaseUrl = params.docBaseUrl || null; - var action = destDict.get('A'), + const docBaseUrl = params.docBaseUrl || null; + let action = destDict.get('A'), url, dest; if (!(0, _primitives.isDict)(action) && destDict.has('Dest')) { action = destDict.get('Dest'); } if ((0, _primitives.isDict)(action)) { - let actionType = action.get('S'); + const actionType = action.get('S'); if (!(0, _primitives.isName)(actionType)) { (0, _util.warn)('parseDestDictionary: Invalid type in Action dictionary.'); return; } - let actionName = actionType.name; + const actionName = actionType.name; switch (actionName) { case 'URI': url = action.get('URI'); @@ -6306,19 +6341,19 @@ var Catalog = function CatalogClosure() { break; case 'Launch': case 'GoToR': - var urlDict = action.get('F'); + const urlDict = action.get('F'); if ((0, _primitives.isDict)(urlDict)) { url = urlDict.get('F') || null; } else if ((0, _util.isString)(urlDict)) { url = urlDict; } - var remoteDest = action.get('D'); + let remoteDest = action.get('D'); if (remoteDest) { if ((0, _primitives.isName)(remoteDest)) { remoteDest = remoteDest.name; } if ((0, _util.isString)(url)) { - let baseUrl = url.split('#')[0]; + const baseUrl = url.split('#')[0]; if ((0, _util.isString)(remoteDest)) { url = baseUrl + '#' + remoteDest; } else if (Array.isArray(remoteDest)) { @@ -6326,29 +6361,29 @@ var Catalog = function CatalogClosure() { } } } - var newWindow = action.get('NewWindow'); + const newWindow = action.get('NewWindow'); if ((0, _util.isBool)(newWindow)) { resultObj.newWindow = newWindow; } break; case 'Named': - var namedAction = action.get('N'); + const namedAction = action.get('N'); if ((0, _primitives.isName)(namedAction)) { resultObj.action = namedAction.name; } break; case 'JavaScript': - var jsAction = action.get('JS'), - js; + const jsAction = action.get('JS'); + let js; if ((0, _primitives.isStream)(jsAction)) { js = (0, _util.bytesToString)(jsAction.getBytes()); } else if ((0, _util.isString)(jsAction)) { js = jsAction; } if (js) { - var URL_OPEN_METHODS = ['app.launchURL', 'window.open']; - var regex = new RegExp('^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') + ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i'); - var jsUrl = regex.exec((0, _util.stringToPDFString)(js)); + const URL_OPEN_METHODS = ['app.launchURL', 'window.open']; + const regex = new RegExp('^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') + ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i'); + const jsUrl = regex.exec((0, _util.stringToPDFString)(js)); if (jsUrl && jsUrl[2]) { url = jsUrl[2]; if (jsUrl[3] === 'true' && jsUrl[1] === 'app.launchURL') { @@ -6358,7 +6393,7 @@ var Catalog = function CatalogClosure() { } } default: - (0, _util.warn)(`parseDestDictionary: Unsupported Action type "${actionName}".`); + (0, _util.warn)(`parseDestDictionary: unsupported action type "${actionName}".`); break; } } else if (destDict.has('Dest')) { @@ -6366,7 +6401,7 @@ var Catalog = function CatalogClosure() { } if ((0, _util.isString)(url)) { url = tryConvertUrlEncoding(url); - var absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl); + const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl); if (absoluteUrl) { resultObj.url = absoluteUrl.href; } @@ -6380,9 +6415,8 @@ var Catalog = function CatalogClosure() { resultObj.dest = dest; } } - }; - return Catalog; -}(); + } +} var XRef = function XRefClosure() { function XRef(stream, pdfManager) { this.stream = stream; @@ -7889,66 +7923,77 @@ var Parser = function ParserClosure() { this.shift(); return imageStream; }, + _findStreamLength(startPos, signature) { + const { stream } = this.lexer; + stream.pos = startPos; + const SCAN_BLOCK_LENGTH = 2048; + const signatureLength = signature.length; + while (stream.pos < stream.end) { + const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); + const scanLength = scanBytes.length - signatureLength; + if (scanLength <= 0) { + break; + } + let pos = 0; + while (pos < scanLength) { + let j = 0; + while (j < signatureLength && scanBytes[pos + j] === signature[j]) { + j++; + } + if (j >= signatureLength) { + stream.pos += pos; + return stream.pos - startPos; + } + pos++; + } + stream.pos += scanLength; + } + return -1; + }, makeStream: function Parser_makeStream(dict, cipherTransform) { var lexer = this.lexer; var stream = lexer.stream; lexer.skipToNextLine(); - var pos = stream.pos - 1; + const startPos = stream.pos - 1; var length = dict.get('Length'); if (!Number.isInteger(length)) { (0, _util.info)('Bad ' + length + ' attribute in stream'); length = 0; } - stream.pos = pos + length; + stream.pos = startPos + length; lexer.nextChar(); if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, 'endstream')) { this.shift(); } else { - stream.pos = pos; - var SCAN_BLOCK_SIZE = 2048; - var ENDSTREAM_SIGNATURE_LENGTH = 9; - var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D]; - var skipped = 0, - found = false, - i, - j; - while (stream.pos < stream.end) { - var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE); - var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH; - if (scanLength <= 0) { - break; - } - found = false; - i = 0; - while (i < scanLength) { - j = 0; - while (j < ENDSTREAM_SIGNATURE_LENGTH && scanBytes[i + j] === ENDSTREAM_SIGNATURE[j]) { - j++; - } - if (j >= ENDSTREAM_SIGNATURE_LENGTH) { - found = true; + const ENDSTREAM_SIGNATURE = new Uint8Array([0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D]); + let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE); + if (actualLength < 0) { + const MAX_TRUNCATION = 1; + for (let i = 1; i <= MAX_TRUNCATION; i++) { + const end = ENDSTREAM_SIGNATURE.length - i; + const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end); + let maybeLength = this._findStreamLength(startPos, TRUNCATED_SIGNATURE); + if (maybeLength >= 0) { + const lastByte = stream.peekBytes(end + 1)[end]; + if (!(0, _util.isSpace)(lastByte)) { + break; + } + (0, _util.info)(`Found "${(0, _util.bytesToString)(TRUNCATED_SIGNATURE)}" when ` + 'searching for endstream command.'); + actualLength = maybeLength; break; } - i++; } - if (found) { - skipped += i; - stream.pos += i; - break; + if (actualLength < 0) { + throw new _util.FormatError('Missing endstream command.'); } - skipped += scanLength; - stream.pos += scanLength; } - if (!found) { - throw new _util.FormatError('Missing endstream'); - } - length = skipped; + length = actualLength; lexer.nextChar(); this.shift(); this.shift(); } this.shift(); - stream = stream.makeSubStream(pos, length, dict); + stream = stream.makeSubStream(startPos, length, dict); if (cipherTransform) { stream = cipherTransform.createStream(stream, length); } @@ -12401,7 +12446,12 @@ let JpegStream = function JpegStreamClosure() { } const jpegImage = new _jpg.JpegImage(jpegOptions); jpegImage.parse(this.bytes); - let data = jpegImage.getData(this.drawWidth, this.drawHeight, this.forceRGB); + let data = jpegImage.getData({ + width: this.drawWidth, + height: this.drawHeight, + forceRGB: this.forceRGB, + isSourcePDF: true + }); this.buffer = data; this.bufferLength = data.length; this.eof = true; @@ -13237,7 +13287,7 @@ var JpegImage = function JpegImageClosure() { } this.numComponents = this.components.length; }, - _getLinearizedBlockData: function getLinearizedBlockData(width, height) { + _getLinearizedBlockData(width, height, isSourcePDF = false) { var scaleX = this.width / width, scaleY = this.height / height; var component, componentScaleX, componentScaleY, blocksPerScanline; @@ -13270,7 +13320,10 @@ var JpegImage = function JpegImageClosure() { } } } - const transform = this._decodeTransform; + let transform = this._decodeTransform; + if (!transform && numComponents === 4 && !isSourcePDF) { + transform = new Int32Array([-256, 255, -256, 255, -256, 255, -256, 255]); + } if (transform) { for (i = 0; i < dataLength;) { for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) { @@ -13280,7 +13333,7 @@ var JpegImage = function JpegImageClosure() { } return data; }, - _isColorConversionNeeded() { + get _isColorConversionNeeded() { if (this.adobe) { return !!this.adobe.transformCode; } @@ -13348,12 +13401,12 @@ var JpegImage = function JpegImageClosure() { } return data.subarray(0, offset); }, - getData: function getData(width, height, forceRGBoutput) { + getData({ width, height, forceRGB = false, isSourcePDF = false }) { if (this.numComponents > 4) { throw new JpegError('Unsupported color mode'); } - var data = this._getLinearizedBlockData(width, height); - if (this.numComponents === 1 && forceRGBoutput) { + var data = this._getLinearizedBlockData(width, height, isSourcePDF); + if (this.numComponents === 1 && forceRGB) { var dataLength = data.length; var rgbData = new Uint8ClampedArray(dataLength * 3); var offset = 0; @@ -13364,15 +13417,15 @@ var JpegImage = function JpegImageClosure() { rgbData[offset++] = grayColor; } return rgbData; - } else if (this.numComponents === 3 && this._isColorConversionNeeded()) { + } else if (this.numComponents === 3 && this._isColorConversionNeeded) { return this._convertYccToRgb(data); } else if (this.numComponents === 4) { - if (this._isColorConversionNeeded()) { - if (forceRGBoutput) { + if (this._isColorConversionNeeded) { + if (forceRGB) { return this._convertYcckToRgb(data); } return this._convertYcckToCmyk(data); - } else if (forceRGBoutput) { + } else if (forceRGB) { return this._convertCmykToRgb(data); } } @@ -16742,122 +16795,120 @@ var _util = __w_pdfjs_require__(2); var _primitives = __w_pdfjs_require__(12); -var ColorSpace = function ColorSpaceClosure() { - function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { - var COMPONENTS = 3; - alpha01 = alpha01 !== 1 ? 0 : alpha01; - var xRatio = w1 / w2; - var yRatio = h1 / h2; - var i, - j, - py, - newIndex = 0, - oldIndex; - var xScaled = new Uint16Array(w2); - var w1Scanline = w1 * COMPONENTS; - for (i = 0; i < w2; i++) { - xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; +function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { + const COMPONENTS = 3; + alpha01 = alpha01 !== 1 ? 0 : alpha01; + let xRatio = w1 / w2; + let yRatio = h1 / h2; + let newIndex = 0, + oldIndex; + let xScaled = new Uint16Array(w2); + let w1Scanline = w1 * COMPONENTS; + for (let i = 0; i < w2; i++) { + xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; + } + for (let i = 0; i < h2; i++) { + const py = Math.floor(i * yRatio) * w1Scanline; + for (let j = 0; j < w2; j++) { + oldIndex = py + xScaled[j]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + newIndex += alpha01; } - for (i = 0; i < h2; i++) { - py = Math.floor(i * yRatio) * w1Scanline; - for (j = 0; j < w2; j++) { - oldIndex = py + xScaled[j]; - dest[newIndex++] = src[oldIndex++]; - dest[newIndex++] = src[oldIndex++]; - dest[newIndex++] = src[oldIndex++]; - newIndex += alpha01; + } +} +class ColorSpace { + constructor(name, numComps) { + if (this.constructor === ColorSpace) { + (0, _util.unreachable)('Cannot initialize ColorSpace.'); + } + this.name = name; + this.numComps = numComps; + } + getRgb(src, srcOffset) { + let rgb = new Uint8ClampedArray(3); + this.getRgbItem(src, srcOffset, rgb, 0); + return rgb; + } + getRgbItem(src, srcOffset, dest, destOffset) { + (0, _util.unreachable)('Should not call ColorSpace.getRgbItem'); + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + (0, _util.unreachable)('Should not call ColorSpace.getRgbBuffer'); + } + getOutputLength(inputLength, alpha01) { + (0, _util.unreachable)('Should not call ColorSpace.getOutputLength'); + } + isPassthrough(bits) { + return false; + } + fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) { + let count = originalWidth * originalHeight; + let rgbBuf = null; + let numComponentColors = 1 << bpc; + let needsResizing = originalHeight !== height || originalWidth !== width; + if (this.isPassthrough(bpc)) { + rgbBuf = comps; + } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { + let allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors); + for (let i = 0; i < numComponentColors; i++) { + allColors[i] = i; } - } - } - function ColorSpace() { - (0, _util.unreachable)('should not call ColorSpace constructor'); - } - ColorSpace.prototype = { - getRgb(src, srcOffset) { - let rgb = new Uint8ClampedArray(3); - this.getRgbItem(src, srcOffset, rgb, 0); - return rgb; - }, - getRgbItem(src, srcOffset, dest, destOffset) { - (0, _util.unreachable)('Should not call ColorSpace.getRgbItem'); - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - (0, _util.unreachable)('Should not call ColorSpace.getRgbBuffer'); - }, - getOutputLength(inputLength, alpha01) { - (0, _util.unreachable)('Should not call ColorSpace.getOutputLength'); - }, - isPassthrough(bits) { - return false; - }, - fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) { - var count = originalWidth * originalHeight; - var rgbBuf = null; - var numComponentColors = 1 << bpc; - var needsResizing = originalHeight !== height || originalWidth !== width; - var i, ii; - if (this.isPassthrough(bpc)) { - rgbBuf = comps; - } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { - var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors); - var key; - for (i = 0; i < numComponentColors; i++) { - allColors[i] = i; - } - var colorMap = new Uint8ClampedArray(numComponentColors * 3); - this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0); - var destPos, rgbPos; - if (!needsResizing) { - destPos = 0; - for (i = 0; i < count; ++i) { - key = comps[i] * 3; - dest[destPos++] = colorMap[key]; - dest[destPos++] = colorMap[key + 1]; - dest[destPos++] = colorMap[key + 2]; - destPos += alpha01; - } - } else { - rgbBuf = new Uint8Array(count * 3); - rgbPos = 0; - for (i = 0; i < count; ++i) { - key = comps[i] * 3; - rgbBuf[rgbPos++] = colorMap[key]; - rgbBuf[rgbPos++] = colorMap[key + 1]; - rgbBuf[rgbPos++] = colorMap[key + 2]; - } + let colorMap = new Uint8ClampedArray(numComponentColors * 3); + this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0); + if (!needsResizing) { + let destPos = 0; + for (let i = 0; i < count; ++i) { + const key = comps[i] * 3; + dest[destPos++] = colorMap[key]; + dest[destPos++] = colorMap[key + 1]; + dest[destPos++] = colorMap[key + 2]; + destPos += alpha01; } } else { - if (!needsResizing) { - this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01); - } else { - rgbBuf = new Uint8ClampedArray(count * 3); - this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0); + rgbBuf = new Uint8Array(count * 3); + let rgbPos = 0; + for (let i = 0; i < count; ++i) { + const key = comps[i] * 3; + rgbBuf[rgbPos++] = colorMap[key]; + rgbBuf[rgbPos++] = colorMap[key + 1]; + rgbBuf[rgbPos++] = colorMap[key + 2]; } } - if (rgbBuf) { - if (needsResizing) { - resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, width, height, alpha01); - } else { - rgbPos = 0; - destPos = 0; - for (i = 0, ii = width * actualHeight; i < ii; i++) { - dest[destPos++] = rgbBuf[rgbPos++]; - dest[destPos++] = rgbBuf[rgbPos++]; - dest[destPos++] = rgbBuf[rgbPos++]; - destPos += alpha01; - } + } else { + if (!needsResizing) { + this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01); + } else { + rgbBuf = new Uint8ClampedArray(count * 3); + this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0); + } + } + if (rgbBuf) { + if (needsResizing) { + resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, width, height, alpha01); + } else { + let destPos = 0, + rgbPos = 0; + for (let i = 0, ii = width * actualHeight; i < ii; i++) { + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + destPos += alpha01; } } - }, - usesZeroToOneRange: true - }; - ColorSpace.parse = function (cs, xref, res, pdfFunctionFactory) { - let IR = ColorSpace.parseToIR(cs, xref, res, pdfFunctionFactory); - return ColorSpace.fromIR(IR); - }; - ColorSpace.fromIR = function (IR) { - var name = Array.isArray(IR) ? IR[0] : IR; - var whitePoint, blackPoint, gamma; + } + } + get usesZeroToOneRange() { + return (0, _util.shadow)(this, 'usesZeroToOneRange', true); + } + static parse(cs, xref, res, pdfFunctionFactory) { + let IR = this.parseToIR(cs, xref, res, pdfFunctionFactory); + return this.fromIR(IR); + } + static fromIR(IR) { + let name = Array.isArray(IR) ? IR[0] : IR; + let whitePoint, blackPoint, gamma; switch (name) { case 'DeviceGrayCS': return this.singletons.gray; @@ -16874,34 +16925,34 @@ var ColorSpace = function ColorSpaceClosure() { whitePoint = IR[1]; blackPoint = IR[2]; gamma = IR[3]; - var matrix = IR[4]; + let matrix = IR[4]; return new CalRGBCS(whitePoint, blackPoint, gamma, matrix); case 'PatternCS': - var basePatternCS = IR[1]; + let basePatternCS = IR[1]; if (basePatternCS) { - basePatternCS = ColorSpace.fromIR(basePatternCS); + basePatternCS = this.fromIR(basePatternCS); } return new PatternCS(basePatternCS); case 'IndexedCS': - var baseIndexedCS = IR[1]; - var hiVal = IR[2]; - var lookup = IR[3]; - return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup); + let baseIndexedCS = IR[1]; + let hiVal = IR[2]; + let lookup = IR[3]; + return new IndexedCS(this.fromIR(baseIndexedCS), hiVal, lookup); case 'AlternateCS': - var numComps = IR[1]; - var alt = IR[2]; - var tintFn = IR[3]; - return new AlternateCS(numComps, ColorSpace.fromIR(alt), tintFn); + let numComps = IR[1]; + let alt = IR[2]; + let tintFn = IR[3]; + return new AlternateCS(numComps, this.fromIR(alt), tintFn); case 'LabCS': whitePoint = IR[1]; blackPoint = IR[2]; - var range = IR[3]; + let range = IR[3]; return new LabCS(whitePoint, blackPoint, range); default: throw new _util.FormatError(`Unknown colorspace name: ${name}`); } - }; - ColorSpace.parseToIR = function (cs, xref, res = null, pdfFunctionFactory) { + } + static parseToIR(cs, xref, res = null, pdfFunctionFactory) { cs = xref.fetchIfRef(cs); if ((0, _primitives.isName)(cs)) { switch (cs.name) { @@ -16923,7 +16974,7 @@ var ColorSpace = function ColorSpaceClosure() { let resCS = colorSpaces.get(cs.name); if (resCS) { if ((0, _primitives.isName)(resCS)) { - return ColorSpace.parseToIR(resCS, xref, res, pdfFunctionFactory); + return this.parseToIR(resCS, xref, res, pdfFunctionFactory); } cs = resCS; break; @@ -16934,8 +16985,8 @@ var ColorSpace = function ColorSpaceClosure() { } } if (Array.isArray(cs)) { - var mode = xref.fetchIfRef(cs[0]).name; - var numComps, params, alt, whitePoint, blackPoint, gamma; + let mode = xref.fetchIfRef(cs[0]).name; + let numComps, params, alt, whitePoint, blackPoint, gamma; switch (mode) { case 'DeviceGray': case 'G': @@ -16957,16 +17008,16 @@ var ColorSpace = function ColorSpaceClosure() { whitePoint = params.getArray('WhitePoint'); blackPoint = params.getArray('BlackPoint'); gamma = params.getArray('Gamma'); - var matrix = params.getArray('Matrix'); + let matrix = params.getArray('Matrix'); return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix]; case 'ICCBased': - var stream = xref.fetchIfRef(cs[1]); - var dict = stream.dict; + let stream = xref.fetchIfRef(cs[1]); + let dict = stream.dict; numComps = dict.get('N'); alt = dict.get('Alternate'); if (alt) { - var altIR = ColorSpace.parseToIR(alt, xref, res, pdfFunctionFactory); - var altCS = ColorSpace.fromIR(altIR, pdfFunctionFactory); + let altIR = this.parseToIR(alt, xref, res, pdfFunctionFactory); + let altCS = this.fromIR(altIR, pdfFunctionFactory); if (altCS.numComps === numComps) { return altIR; } @@ -16981,40 +17032,40 @@ var ColorSpace = function ColorSpaceClosure() { } break; case 'Pattern': - var basePatternCS = cs[1] || null; + let basePatternCS = cs[1] || null; if (basePatternCS) { - basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res, pdfFunctionFactory); + basePatternCS = this.parseToIR(basePatternCS, xref, res, pdfFunctionFactory); } return ['PatternCS', basePatternCS]; case 'Indexed': case 'I': - var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res, pdfFunctionFactory); - var hiVal = xref.fetchIfRef(cs[2]) + 1; - var lookup = xref.fetchIfRef(cs[3]); + let baseIndexedCS = this.parseToIR(cs[1], xref, res, pdfFunctionFactory); + let hiVal = xref.fetchIfRef(cs[2]) + 1; + let lookup = xref.fetchIfRef(cs[3]); if ((0, _primitives.isStream)(lookup)) { lookup = lookup.getBytes(); } return ['IndexedCS', baseIndexedCS, hiVal, lookup]; case 'Separation': case 'DeviceN': - var name = xref.fetchIfRef(cs[1]); + let name = xref.fetchIfRef(cs[1]); numComps = Array.isArray(name) ? name.length : 1; - alt = ColorSpace.parseToIR(cs[2], xref, res, pdfFunctionFactory); + alt = this.parseToIR(cs[2], xref, res, pdfFunctionFactory); let tintFn = pdfFunctionFactory.create(xref.fetchIfRef(cs[3])); return ['AlternateCS', numComps, alt, tintFn]; case 'Lab': params = xref.fetchIfRef(cs[1]); whitePoint = params.getArray('WhitePoint'); blackPoint = params.getArray('BlackPoint'); - var range = params.getArray('Range'); + let range = params.getArray('Range'); return ['LabCS', whitePoint, blackPoint, range]; default: throw new _util.FormatError(`unimplemented color space object "${mode}"`); } } throw new _util.FormatError(`unrecognized color space object: "${cs}"`); - }; - ColorSpace.isDefaultDecode = function (decode, n) { + } + static isDefaultDecode(decode, n) { if (!Array.isArray(decode)) { return true; } @@ -17022,112 +17073,97 @@ var ColorSpace = function ColorSpaceClosure() { (0, _util.warn)('The decode map is not the correct length'); return true; } - for (var i = 0, ii = decode.length; i < ii; i += 2) { + for (let i = 0, ii = decode.length; i < ii; i += 2) { if (decode[i] !== 0 || decode[i + 1] !== 1) { return false; } } return true; - }; - ColorSpace.singletons = { - get gray() { - return (0, _util.shadow)(this, 'gray', new DeviceGrayCS()); - }, - get rgb() { - return (0, _util.shadow)(this, 'rgb', new DeviceRgbCS()); - }, - get cmyk() { - return (0, _util.shadow)(this, 'cmyk', new DeviceCmykCS()); - } - }; - return ColorSpace; -}(); -var AlternateCS = function AlternateCSClosure() { - function AlternateCS(numComps, base, tintFn) { - this.name = 'Alternate'; - this.numComps = numComps; - this.defaultColor = new Float32Array(numComps); - for (var i = 0; i < numComps; ++i) { - this.defaultColor[i] = 1; - } + } + static get singletons() { + return (0, _util.shadow)(this, 'singletons', { + get gray() { + return (0, _util.shadow)(this, 'gray', new DeviceGrayCS()); + }, + get rgb() { + return (0, _util.shadow)(this, 'rgb', new DeviceRgbCS()); + }, + get cmyk() { + return (0, _util.shadow)(this, 'cmyk', new DeviceCmykCS()); + } + }); + } +} +class AlternateCS extends ColorSpace { + constructor(numComps, base, tintFn) { + super('Alternate', numComps); this.base = base; this.tintFn = tintFn; this.tmpBuf = new Float32Array(base.numComps); } - AlternateCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - var tmpBuf = this.tmpBuf; - this.tintFn(src, srcOffset, tmpBuf, 0); - this.base.getRgbItem(tmpBuf, 0, dest, destOffset); - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var tintFn = this.tintFn; - var base = this.base; - var scale = 1 / ((1 << bits) - 1); - var baseNumComps = base.numComps; - var usesZeroToOneRange = base.usesZeroToOneRange; - var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0; - var pos = isPassthrough ? destOffset : 0; - let baseBuf = isPassthrough ? dest : new Uint8ClampedArray(baseNumComps * count); - var numComps = this.numComps; - var scaled = new Float32Array(numComps); - var tinted = new Float32Array(baseNumComps); - var i, j; - for (i = 0; i < count; i++) { - for (j = 0; j < numComps; j++) { - scaled[j] = src[srcOffset++] * scale; - } - tintFn(scaled, 0, tinted, 0); - if (usesZeroToOneRange) { - for (j = 0; j < baseNumComps; j++) { - baseBuf[pos++] = tinted[j] * 255; - } - } else { - base.getRgbItem(tinted, 0, baseBuf, pos); - pos += baseNumComps; - } + getRgbItem(src, srcOffset, dest, destOffset) { + let tmpBuf = this.tmpBuf; + this.tintFn(src, srcOffset, tmpBuf, 0); + this.base.getRgbItem(tmpBuf, 0, dest, destOffset); + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + let tintFn = this.tintFn; + let base = this.base; + let scale = 1 / ((1 << bits) - 1); + let baseNumComps = base.numComps; + let usesZeroToOneRange = base.usesZeroToOneRange; + let isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0; + let pos = isPassthrough ? destOffset : 0; + let baseBuf = isPassthrough ? dest : new Uint8ClampedArray(baseNumComps * count); + let numComps = this.numComps; + let scaled = new Float32Array(numComps); + let tinted = new Float32Array(baseNumComps); + let i, j; + for (i = 0; i < count; i++) { + for (j = 0; j < numComps; j++) { + scaled[j] = src[srcOffset++] * scale; } - if (!isPassthrough) { - base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); + tintFn(scaled, 0, tinted, 0); + if (usesZeroToOneRange) { + for (j = 0; j < baseNumComps; j++) { + baseBuf[pos++] = tinted[j] * 255; + } + } else { + base.getRgbItem(tinted, 0, baseBuf, pos); + pos += baseNumComps; } - }, - getOutputLength(inputLength, alpha01) { - return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true - }; - return AlternateCS; -}(); -var PatternCS = function PatternCSClosure() { - function PatternCS(baseCS) { - this.name = 'Pattern'; + } + if (!isPassthrough) { + base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); + } + } + getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01); + } + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + } +} +class PatternCS extends ColorSpace { + constructor(baseCS) { + super('Pattern', null); this.base = baseCS; } - PatternCS.prototype = {}; - return PatternCS; -}(); -var IndexedCS = function IndexedCSClosure() { - function IndexedCS(base, highVal, lookup) { - this.name = 'Indexed'; - this.numComps = 1; - this.defaultColor = new Uint8Array(this.numComps); +} +class IndexedCS extends ColorSpace { + constructor(base, highVal, lookup) { + super('Indexed', 1); this.base = base; this.highVal = highVal; - var baseNumComps = base.numComps; - var length = baseNumComps * highVal; + let baseNumComps = base.numComps; + let length = baseNumComps * highVal; if ((0, _primitives.isStream)(lookup)) { this.lookup = new Uint8Array(length); - var bytes = lookup.getBytes(length); + let bytes = lookup.getBytes(length); this.lookup.set(bytes); } else if ((0, _util.isString)(lookup)) { this.lookup = new Uint8Array(length); - for (var i = 0; i < length; ++i) { + for (let i = 0; i < length; ++i) { this.lookup[i] = lookup.charCodeAt(i); } } else if (lookup instanceof Uint8Array) { @@ -17136,272 +17172,193 @@ var IndexedCS = function IndexedCSClosure() { throw new _util.FormatError(`Unrecognized lookup table: ${lookup}`); } } - IndexedCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - var numComps = this.base.numComps; - var start = src[srcOffset] * numComps; - this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var base = this.base; - var numComps = base.numComps; - var outputDelta = base.getOutputLength(numComps, alpha01); - var lookup = this.lookup; - for (var i = 0; i < count; ++i) { - var lookupPos = src[srcOffset++] * numComps; - base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); - destOffset += outputDelta; - } - }, - getOutputLength(inputLength, alpha01) { - return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return true; - }, - usesZeroToOneRange: true - }; - return IndexedCS; -}(); -var DeviceGrayCS = function DeviceGrayCSClosure() { - function DeviceGrayCS() { - this.name = 'DeviceGray'; - this.numComps = 1; - this.defaultColor = new Float32Array(this.numComps); + getRgbItem(src, srcOffset, dest, destOffset) { + let numComps = this.base.numComps; + let start = src[srcOffset] * numComps; + this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); } - DeviceGrayCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - let c = src[srcOffset] * 255; - dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var scale = 255 / ((1 << bits) - 1); - var j = srcOffset, - q = destOffset; - for (var i = 0; i < count; ++i) { - let c = scale * src[j++]; - dest[q++] = c; - dest[q++] = c; - dest[q++] = c; - q += alpha01; - } - }, - getOutputLength(inputLength, alpha01) { - return inputLength * (3 + alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true - }; - return DeviceGrayCS; -}(); -var DeviceRgbCS = function DeviceRgbCSClosure() { - function DeviceRgbCS() { - this.name = 'DeviceRGB'; - this.numComps = 3; - this.defaultColor = new Float32Array(this.numComps); + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + let base = this.base; + let numComps = base.numComps; + let outputDelta = base.getOutputLength(numComps, alpha01); + let lookup = this.lookup; + for (let i = 0; i < count; ++i) { + let lookupPos = src[srcOffset++] * numComps; + base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); + destOffset += outputDelta; + } } - DeviceRgbCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, - getRgbItem(src, srcOffset, dest, destOffset) { - dest[destOffset] = src[srcOffset] * 255; - dest[destOffset + 1] = src[srcOffset + 1] * 255; - dest[destOffset + 2] = src[srcOffset + 2] * 255; - }, - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (bits === 8 && alpha01 === 0) { - dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); - return; - } - var scale = 255 / ((1 << bits) - 1); - var j = srcOffset, - q = destOffset; - for (var i = 0; i < count; ++i) { - dest[q++] = scale * src[j++]; - dest[q++] = scale * src[j++]; - dest[q++] = scale * src[j++]; - q += alpha01; - } - }, - getOutputLength(inputLength, alpha01) { - return inputLength * (3 + alpha01) / 3 | 0; - }, - isPassthrough(bits) { - return bits === 8; - }, - fillRgb: ColorSpace.prototype.fillRgb, - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true - }; - return DeviceRgbCS; -}(); -var DeviceCmykCS = function DeviceCmykCSClosure() { + getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); + } + isDefaultDecode(decodeMap) { + return true; + } +} +class DeviceGrayCS extends ColorSpace { + constructor() { + super('DeviceGray', 1); + } + getRgbItem(src, srcOffset, dest, destOffset) { + let c = src[srcOffset] * 255; + dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + let scale = 255 / ((1 << bits) - 1); + let j = srcOffset, + q = destOffset; + for (let i = 0; i < count; ++i) { + let c = scale * src[j++]; + dest[q++] = c; + dest[q++] = c; + dest[q++] = c; + q += alpha01; + } + } + getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01); + } + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + } +} +class DeviceRgbCS extends ColorSpace { + constructor() { + super('DeviceRGB', 3); + } + getRgbItem(src, srcOffset, dest, destOffset) { + dest[destOffset] = src[srcOffset] * 255; + dest[destOffset + 1] = src[srcOffset + 1] * 255; + dest[destOffset + 2] = src[srcOffset + 2] * 255; + } + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (bits === 8 && alpha01 === 0) { + dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); + return; + } + let scale = 255 / ((1 << bits) - 1); + let j = srcOffset, + q = destOffset; + for (let i = 0; i < count; ++i) { + dest[q++] = scale * src[j++]; + dest[q++] = scale * src[j++]; + dest[q++] = scale * src[j++]; + q += alpha01; + } + } + getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01) / 3 | 0; + } + isPassthrough(bits) { + return bits === 8; + } + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + } +} +const DeviceCmykCS = function DeviceCmykCSClosure() { function convertToRgb(src, srcOffset, srcScale, dest, destOffset) { - var c = src[srcOffset] * srcScale; - var m = src[srcOffset + 1] * srcScale; - var y = src[srcOffset + 2] * srcScale; - var k = src[srcOffset + 3] * srcScale; + let c = src[srcOffset] * srcScale; + let m = src[srcOffset + 1] * srcScale; + let y = src[srcOffset + 2] * srcScale; + let k = src[srcOffset + 3] * srcScale; dest[destOffset] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) + k * (-21.86122147463605 * k - 189.48180835922747); dest[destOffset + 1] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + k * (-20.737325471181034 * k - 187.80453709719578); dest[destOffset + 2] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505) + k * (-22.33816807309886 * k - 180.12613974708367); } - function DeviceCmykCS() { - this.name = 'DeviceCMYK'; - this.numComps = 4; - this.defaultColor = new Float32Array(this.numComps); - this.defaultColor[3] = 1; - } - DeviceCmykCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class DeviceCmykCS extends ColorSpace { + constructor() { + super('DeviceCMYK', 4); + } getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(src, srcOffset, 1, dest, destOffset); - }, + } getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var scale = 1 / ((1 << bits) - 1); - for (var i = 0; i < count; i++) { + let scale = 1 / ((1 << bits) - 1); + for (let i = 0; i < count; i++) { convertToRgb(src, srcOffset, scale, dest, destOffset); srcOffset += 4; destOffset += 3 + alpha01; } - }, + } getOutputLength(inputLength, alpha01) { return inputLength / 4 * (3 + alpha01) | 0; - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true - }; - return DeviceCmykCS; -}(); -var CalGrayCS = function CalGrayCSClosure() { - function CalGrayCS(whitePoint, blackPoint, gamma) { - this.name = 'CalGray'; - this.numComps = 1; - this.defaultColor = new Float32Array(this.numComps); - if (!whitePoint) { - throw new _util.FormatError('WhitePoint missing - required for color space CalGray'); - } - blackPoint = blackPoint || [0, 0, 0]; - gamma = gamma || 1; - this.XW = whitePoint[0]; - this.YW = whitePoint[1]; - this.ZW = whitePoint[2]; - this.XB = blackPoint[0]; - this.YB = blackPoint[1]; - this.ZB = blackPoint[2]; - this.G = gamma; - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { - throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); - } - if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - (0, _util.info)('Invalid BlackPoint for ' + this.name + ', falling back to default'); - this.XB = this.YB = this.ZB = 0; - } - if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { - (0, _util.warn)(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + ', ZB: ' + this.ZB + ', only default values are supported.'); - } - if (this.G < 1) { - (0, _util.info)('Invalid Gamma: ' + this.G + ' for ' + this.name + ', falling back to default'); - this.G = 1; } } + return DeviceCmykCS; +}(); +const CalGrayCS = function CalGrayCSClosure() { function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { - var A = src[srcOffset] * scale; - var AG = Math.pow(A, cs.G); - var L = cs.YW * AG; + let A = src[srcOffset] * scale; + let AG = Math.pow(A, cs.G); + let L = cs.YW * AG; let val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0); dest[destOffset] = val; dest[destOffset + 1] = val; dest[destOffset + 2] = val; } - CalGrayCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class CalGrayCS extends ColorSpace { + constructor(whitePoint, blackPoint, gamma) { + super('CalGray', 1); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space CalGray'); + } + blackPoint = blackPoint || [0, 0, 0]; + gamma = gamma || 1; + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + this.G = gamma; + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); + } + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + (0, _util.info)(`Invalid BlackPoint for ${this.name}, falling back to default.`); + this.XB = this.YB = this.ZB = 0; + } + if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { + (0, _util.warn)(`${this.name}, BlackPoint: XB: ${this.XB}, YB: ${this.YB}, ` + `ZB: ${this.ZB}, only default values are supported.`); + } + if (this.G < 1) { + (0, _util.info)(`Invalid Gamma: ${this.G} for ${this.name}, ` + 'falling back to default.'); + this.G = 1; + } + } getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(this, src, srcOffset, dest, destOffset, 1); - }, + } getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var scale = 1 / ((1 << bits) - 1); - for (var i = 0; i < count; ++i) { + let scale = 1 / ((1 << bits) - 1); + for (let i = 0; i < count; ++i) { convertToRgb(this, src, srcOffset, dest, destOffset, scale); srcOffset += 1; destOffset += 3 + alpha01; } - }, + } getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01); - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true - }; - return CalGrayCS; -}(); -var CalRGBCS = function CalRGBCSClosure() { - var BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]); - var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]); - var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252]); - var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); - var tempNormalizeMatrix = new Float32Array(3); - var tempConvertMatrix1 = new Float32Array(3); - var tempConvertMatrix2 = new Float32Array(3); - var DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0; - function CalRGBCS(whitePoint, blackPoint, gamma, matrix) { - this.name = 'CalRGB'; - this.numComps = 3; - this.defaultColor = new Float32Array(this.numComps); - if (!whitePoint) { - throw new _util.FormatError('WhitePoint missing - required for color space CalRGB'); - } - blackPoint = blackPoint || new Float32Array(3); - gamma = gamma || new Float32Array([1, 1, 1]); - matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); - var XW = whitePoint[0]; - var YW = whitePoint[1]; - var ZW = whitePoint[2]; - this.whitePoint = whitePoint; - var XB = blackPoint[0]; - var YB = blackPoint[1]; - var ZB = blackPoint[2]; - this.blackPoint = blackPoint; - this.GR = gamma[0]; - this.GG = gamma[1]; - this.GB = gamma[2]; - this.MXA = matrix[0]; - this.MYA = matrix[1]; - this.MZA = matrix[2]; - this.MXB = matrix[3]; - this.MYB = matrix[4]; - this.MZB = matrix[5]; - this.MXC = matrix[6]; - this.MYC = matrix[7]; - this.MZC = matrix[8]; - if (XW < 0 || ZW < 0 || YW !== 1) { - throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); - } - if (XB < 0 || YB < 0 || ZB < 0) { - (0, _util.info)('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB + ', ' + ZB + '], falling back to default'); - this.blackPoint = new Float32Array(3); - } - if (this.GR < 0 || this.GG < 0 || this.GB < 0) { - (0, _util.info)('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB + '] for ' + this.name + ', falling back to default'); - this.GR = this.GG = this.GB = 1; } } + return CalGrayCS; +}(); +const CalRGBCS = function CalRGBCSClosure() { + const BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]); + const BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]); + const SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252]); + const FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); + let tempNormalizeMatrix = new Float32Array(3); + let tempConvertMatrix1 = new Float32Array(3); + let tempConvertMatrix2 = new Float32Array(3); + const DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0; function matrixProduct(a, b, result) { result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2]; @@ -17413,9 +17370,9 @@ var CalRGBCS = function CalRGBCSClosure() { result[2] = LMS[2] * 1 / sourceWhitePoint[2]; } function convertToD65(sourceWhitePoint, LMS, result) { - var D65X = 0.95047; - var D65Y = 1; - var D65Z = 1.08883; + const D65X = 0.95047; + const D65Y = 1; + const D65Z = 1.08883; result[0] = LMS[0] * D65X / sourceWhitePoint[0]; result[1] = LMS[1] * D65Y / sourceWhitePoint[1]; result[2] = LMS[2] * D65Z / sourceWhitePoint[2]; @@ -17445,19 +17402,19 @@ var CalRGBCS = function CalRGBCSClosure() { result[2] = XYZ_Flat[2]; return; } - var zeroDecodeL = decodeL(0); - var X_DST = zeroDecodeL; - var X_SRC = decodeL(sourceBlackPoint[0]); - var Y_DST = zeroDecodeL; - var Y_SRC = decodeL(sourceBlackPoint[1]); - var Z_DST = zeroDecodeL; - var Z_SRC = decodeL(sourceBlackPoint[2]); - var X_Scale = (1 - X_DST) / (1 - X_SRC); - var X_Offset = 1 - X_Scale; - var Y_Scale = (1 - Y_DST) / (1 - Y_SRC); - var Y_Offset = 1 - Y_Scale; - var Z_Scale = (1 - Z_DST) / (1 - Z_SRC); - var Z_Offset = 1 - Z_Scale; + let zeroDecodeL = decodeL(0); + let X_DST = zeroDecodeL; + let X_SRC = decodeL(sourceBlackPoint[0]); + let Y_DST = zeroDecodeL; + let Y_SRC = decodeL(sourceBlackPoint[1]); + let Z_DST = zeroDecodeL; + let Z_SRC = decodeL(sourceBlackPoint[2]); + let X_Scale = (1 - X_DST) / (1 - X_SRC); + let X_Offset = 1 - X_Scale; + let Y_Scale = (1 - Y_DST) / (1 - Y_SRC); + let Y_Offset = 1 - Y_Scale; + let Z_Scale = (1 - Z_DST) / (1 - Z_SRC); + let Z_Offset = 1 - Z_Scale; result[0] = XYZ_Flat[0] * X_Scale + X_Offset; result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset; result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset; @@ -17469,107 +17426,109 @@ var CalRGBCS = function CalRGBCSClosure() { result[2] = XYZ_In[2]; return; } - var LMS = result; + let LMS = result; matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); - var LMS_Flat = tempNormalizeMatrix; + let LMS_Flat = tempNormalizeMatrix; convertToFlat(sourceWhitePoint, LMS, LMS_Flat); matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result); } function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) { - var LMS = result; + let LMS = result; matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); - var LMS_D65 = tempNormalizeMatrix; + let LMS_D65 = tempNormalizeMatrix; convertToD65(sourceWhitePoint, LMS, LMS_D65); matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result); } function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { - var A = adjustToRange(0, 1, src[srcOffset] * scale); - var B = adjustToRange(0, 1, src[srcOffset + 1] * scale); - var C = adjustToRange(0, 1, src[srcOffset + 2] * scale); - var AGR = Math.pow(A, cs.GR); - var BGG = Math.pow(B, cs.GG); - var CGB = Math.pow(C, cs.GB); - var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; - var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; - var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; - var XYZ = tempConvertMatrix1; + let A = adjustToRange(0, 1, src[srcOffset] * scale); + let B = adjustToRange(0, 1, src[srcOffset + 1] * scale); + let C = adjustToRange(0, 1, src[srcOffset + 2] * scale); + let AGR = Math.pow(A, cs.GR); + let BGG = Math.pow(B, cs.GG); + let CGB = Math.pow(C, cs.GB); + let X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; + let Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; + let Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; + let XYZ = tempConvertMatrix1; XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; - var XYZ_Flat = tempConvertMatrix2; + let XYZ_Flat = tempConvertMatrix2; normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat); - var XYZ_Black = tempConvertMatrix1; + let XYZ_Black = tempConvertMatrix1; compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black); - var XYZ_D65 = tempConvertMatrix2; + let XYZ_D65 = tempConvertMatrix2; normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65); - var SRGB = tempConvertMatrix1; + let SRGB = tempConvertMatrix1; matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB); dest[destOffset] = sRGBTransferFunction(SRGB[0]) * 255; dest[destOffset + 1] = sRGBTransferFunction(SRGB[1]) * 255; dest[destOffset + 2] = sRGBTransferFunction(SRGB[2]) * 255; } - CalRGBCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class CalRGBCS extends ColorSpace { + constructor(whitePoint, blackPoint, gamma, matrix) { + super('CalRGB', 3); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space CalRGB'); + } + blackPoint = blackPoint || new Float32Array(3); + gamma = gamma || new Float32Array([1, 1, 1]); + matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); + let XW = whitePoint[0]; + let YW = whitePoint[1]; + let ZW = whitePoint[2]; + this.whitePoint = whitePoint; + let XB = blackPoint[0]; + let YB = blackPoint[1]; + let ZB = blackPoint[2]; + this.blackPoint = blackPoint; + this.GR = gamma[0]; + this.GG = gamma[1]; + this.GB = gamma[2]; + this.MXA = matrix[0]; + this.MYA = matrix[1]; + this.MZA = matrix[2]; + this.MXB = matrix[3]; + this.MYB = matrix[4]; + this.MZB = matrix[5]; + this.MXC = matrix[6]; + this.MYC = matrix[7]; + this.MZC = matrix[8]; + if (XW < 0 || ZW < 0 || YW !== 1) { + throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); + } + if (XB < 0 || YB < 0 || ZB < 0) { + (0, _util.info)(`Invalid BlackPoint for ${this.name} [${XB}, ${YB}, ${ZB}], ` + 'falling back to default.'); + this.blackPoint = new Float32Array(3); + } + if (this.GR < 0 || this.GG < 0 || this.GB < 0) { + (0, _util.info)(`Invalid Gamma [${this.GR}, ${this.GG}, ${this.GB}] for ` + `${this.name}, falling back to default.`); + this.GR = this.GG = this.GB = 1; + } + } getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(this, src, srcOffset, dest, destOffset, 1); - }, + } getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var scale = 1 / ((1 << bits) - 1); - for (var i = 0; i < count; ++i) { + let scale = 1 / ((1 << bits) - 1); + for (let i = 0; i < count; ++i) { convertToRgb(this, src, srcOffset, dest, destOffset, scale); srcOffset += 3; destOffset += 3 + alpha01; } - }, + } getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01) / 3 | 0; - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - }, - usesZeroToOneRange: true - }; - return CalRGBCS; -}(); -var LabCS = function LabCSClosure() { - function LabCS(whitePoint, blackPoint, range) { - this.name = 'Lab'; - this.numComps = 3; - this.defaultColor = new Float32Array(this.numComps); - if (!whitePoint) { - throw new _util.FormatError('WhitePoint missing - required for color space Lab'); - } - blackPoint = blackPoint || [0, 0, 0]; - range = range || [-100, 100, -100, 100]; - this.XW = whitePoint[0]; - this.YW = whitePoint[1]; - this.ZW = whitePoint[2]; - this.amin = range[0]; - this.amax = range[1]; - this.bmin = range[2]; - this.bmax = range[3]; - this.XB = blackPoint[0]; - this.YB = blackPoint[1]; - this.ZB = blackPoint[2]; - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { - throw new _util.FormatError('Invalid WhitePoint components, no fallback available'); - } - if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - (0, _util.info)('Invalid BlackPoint, falling back to default'); - this.XB = this.YB = this.ZB = 0; - } - if (this.amin > this.amax || this.bmin > this.bmax) { - (0, _util.info)('Invalid Range, falling back to defaults'); - this.amin = -100; - this.amax = 100; - this.bmin = -100; - this.bmax = 100; } } + return CalRGBCS; +}(); +const LabCS = function LabCSClosure() { function fn_g(x) { - var result; + let result; if (x >= 6 / 29) { result = x * x * x; } else { @@ -17581,9 +17540,9 @@ var LabCS = function LabCSClosure() { return low2 + value * (high2 - low2) / high1; } function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) { - var Ls = src[srcOffset]; - var as = src[srcOffset + 1]; - var bs = src[srcOffset + 2]; + let Ls = src[srcOffset]; + let as = src[srcOffset + 1]; + let bs = src[srcOffset + 2]; if (maxVal !== false) { Ls = decode(Ls, maxVal, 0, 100); as = decode(as, maxVal, cs.amin, cs.amax); @@ -17591,13 +17550,13 @@ var LabCS = function LabCSClosure() { } as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as; bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs; - var M = (Ls + 16) / 116; - var L = M + as / 500; - var N = M - bs / 200; - var X = cs.XW * fn_g(L); - var Y = cs.YW * fn_g(M); - var Z = cs.ZW * fn_g(N); - var r, g, b; + let M = (Ls + 16) / 116; + let L = M + as / 500; + let N = M - bs / 200; + let X = cs.XW * fn_g(L); + let Y = cs.YW * fn_g(M); + let Z = cs.ZW * fn_g(N); + let r, g, b; if (cs.ZW < 1) { r = X * 3.1339 + Y * -1.6170 + Z * -0.4906; g = X * -0.9785 + Y * 1.9160 + Z * 0.0333; @@ -17611,29 +17570,60 @@ var LabCS = function LabCSClosure() { dest[destOffset + 1] = Math.sqrt(g) * 255; dest[destOffset + 2] = Math.sqrt(b) * 255; } - LabCS.prototype = { - getRgb: ColorSpace.prototype.getRgb, + class LabCS extends ColorSpace { + constructor(whitePoint, blackPoint, range) { + super('Lab', 3); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space Lab'); + } + blackPoint = blackPoint || [0, 0, 0]; + range = range || [-100, 100, -100, 100]; + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + this.amin = range[0]; + this.amax = range[1]; + this.bmin = range[2]; + this.bmax = range[3]; + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new _util.FormatError('Invalid WhitePoint components, no fallback available'); + } + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + (0, _util.info)('Invalid BlackPoint, falling back to default'); + this.XB = this.YB = this.ZB = 0; + } + if (this.amin > this.amax || this.bmin > this.bmax) { + (0, _util.info)('Invalid Range, falling back to defaults'); + this.amin = -100; + this.amax = 100; + this.bmin = -100; + this.bmax = 100; + } + } getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(this, src, srcOffset, false, dest, destOffset); - }, + } getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - var maxVal = (1 << bits) - 1; - for (var i = 0; i < count; i++) { + let maxVal = (1 << bits) - 1; + for (let i = 0; i < count; i++) { convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); srcOffset += 3; destOffset += 3 + alpha01; } - }, + } getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01) / 3 | 0; - }, - isPassthrough: ColorSpace.prototype.isPassthrough, - fillRgb: ColorSpace.prototype.fillRgb, + } isDefaultDecode(decodeMap) { return true; - }, - usesZeroToOneRange: false - }; + } + get usesZeroToOneRange() { + return (0, _util.shadow)(this, 'usesZeroToOneRange', false); + } + } return LabCS; }(); exports.ColorSpace = ColorSpace; @@ -20069,6 +20059,14 @@ var PartialEvaluator = function PartialEvaluatorClosure() { textContentItem.initialized = false; textContentItem.str.length = 0; } + function isIdenticalSetFont(name, size) { + return textState.font && name === textState.fontName && size === textState.fontSize; + } + function handleBeginText() { + flushTextContentItem(); + textState.textMatrix = _util.IDENTITY_MATRIX.slice(); + textState.textLineMatrix = _util.IDENTITY_MATRIX.slice(); + } function enqueueChunk() { let length = textContent.items.length; if (length > 0) { @@ -20094,6 +20092,7 @@ var PartialEvaluator = function PartialEvaluatorClosure() { var stop, operation = {}, args = []; + let pendingBeginText = false; while (!(stop = timeSlotManager.check())) { args.length = 0; operation.args = args; @@ -20101,14 +20100,27 @@ var PartialEvaluator = function PartialEvaluatorClosure() { break; } textState = stateManager.state; - var fn = operation.fn; + var fn = operation.fn | 0; args = operation.args; var advance, diff; - switch (fn | 0) { + if (pendingBeginText) { + if (fn === _util.OPS.setFont) { + const fontNameArg = args[0].name, + fontSizeArg = args[1]; + if (isIdenticalSetFont(fontNameArg, fontSizeArg)) { + continue; + } + } + if (fn !== _util.OPS.setTextMatrix) { + handleBeginText(); + } + pendingBeginText = false; + } + switch (fn) { case _util.OPS.setFont: var fontNameArg = args[0].name, fontSizeArg = args[1]; - if (textState.font && fontNameArg === textState.fontName && fontSizeArg === textState.fontSize) { + if (isIdenticalSetFont(fontNameArg, fontSizeArg)) { break; } flushTextContentItem(); @@ -20174,9 +20186,11 @@ var PartialEvaluator = function PartialEvaluatorClosure() { textState.wordSpacing = args[0]; break; case _util.OPS.beginText: - flushTextContentItem(); - textState.textMatrix = _util.IDENTITY_MATRIX.slice(); - textState.textLineMatrix = _util.IDENTITY_MATRIX.slice(); + if (combineTextItems) { + pendingBeginText = true; + break; + } + handleBeginText(); break; case _util.OPS.showSpacedText: var items = args[0]; diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index dd60a0de17d4..4258538ee4aa 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2017 Mozilla Foundation + * Copyright 2018 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -396,7 +396,7 @@ let PDFViewerApplication = { this.bindWindowEvents(); let appContainer = appConfig.appContainer || document.documentElement; this.l10n.translate(appContainer).then(() => { - this.eventBus.dispatch('localized'); + this.eventBus.dispatch('localized', { source: this }); }); this.initialized = true; }); @@ -480,7 +480,8 @@ let PDFViewerApplication = { let { appConfig } = this; return new Promise((resolve, reject) => { this.overlayManager = new _overlay_manager.OverlayManager(); - let eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(); + const dispatchToDOM = _app_options.AppOptions.get('eventBusDispatchToDOM'); + let eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(dispatchToDOM); this.eventBus = eventBus; let pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); pdfRenderingQueue.onIdle = this.cleanup.bind(this); @@ -885,6 +886,7 @@ let PDFViewerApplication = { this.downloadComplete = true; this.loadingBar.hide(); firstPagePromise.then(() => { + this.eventBus.dispatch('documentloaded', { source: this }); this.eventBus.dispatch('documentload', { source: this }); }); }); @@ -960,6 +962,7 @@ let PDFViewerApplication = { scrollMode, spreadMode }); + this.eventBus.dispatch('documentinit', { source: this }); if (!this.isViewerEmbedded) { pdfViewer.focus(); } @@ -1219,13 +1222,16 @@ let PDFViewerApplication = { eventBus.dispatch('resize', { source: window }); }; _boundEvents.windowHashChange = () => { - eventBus.dispatch('hashchange', { hash: document.location.hash.substring(1) }); + eventBus.dispatch('hashchange', { + source: window, + hash: document.location.hash.substring(1) + }); }; _boundEvents.windowBeforePrint = () => { - eventBus.dispatch('beforeprint'); + eventBus.dispatch('beforeprint', { source: window }); }; _boundEvents.windowAfterPrint = () => { - eventBus.dispatch('afterprint'); + eventBus.dispatch('afterprint', { source: window }); }; window.addEventListener('wheel', webViewerWheel); window.addEventListener('click', webViewerClick); @@ -2284,8 +2290,11 @@ let animationStarted = new Promise(function (resolve) { window.requestAnimationFrame(resolve); }); class EventBus { - constructor() { + constructor({ + dispatchToDOM = false + } = {}) { this._listeners = Object.create(null); + this._dispatchToDOM = dispatchToDOM === true; } on(eventName, listener) { let eventListeners = this._listeners[eventName]; @@ -2306,12 +2315,40 @@ class EventBus { dispatch(eventName) { let eventListeners = this._listeners[eventName]; if (!eventListeners || eventListeners.length === 0) { + if (this._dispatchToDOM) { + this._dispatchDOMEvent(eventName); + } return; } let args = Array.prototype.slice.call(arguments, 1); eventListeners.slice(0).forEach(function (listener) { listener.apply(null, args); }); + if (this._dispatchToDOM) { + this._dispatchDOMEvent(eventName, args); + } + } + _dispatchDOMEvent(eventName, args = null) { + if (!this._dispatchToDOM) { + return; + } + const details = Object.create(null); + if (args && args.length > 0) { + const obj = args[0]; + for (let key in obj) { + const value = obj[key]; + if (key === 'source') { + if (value === window || value === document) { + return; + } + continue; + } + details[key] = value; + } + } + const event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, details); + document.dispatchEvent(event); } } function clamp(v, min, max) { @@ -3141,6 +3178,10 @@ const defaultOptions = { value: false, kind: OptionKind.VIEWER }, + eventBusDispatchToDOM: { + value: false, + kind: OptionKind.VIEWER + }, externalLinkRel: { value: 'noopener noreferrer nofollow', kind: OptionKind.VIEWER @@ -3408,12 +3449,13 @@ function attachDOMEventsToEventBus(eventBus) { }); } let globalEventBus = null; -function getGlobalEventBus() { - if (globalEventBus) { - return globalEventBus; +function getGlobalEventBus(dispatchToDOM = false) { + if (!globalEventBus) { + globalEventBus = new _ui_utils.EventBus({ dispatchToDOM }); + if (!dispatchToDOM) { + attachDOMEventsToEventBus(globalEventBus); + } } - globalEventBus = new _ui_utils.EventBus(); - attachDOMEventsToEventBus(globalEventBus); return globalEventBus; } exports.attachDOMEventsToEventBus = attachDOMEventsToEventBus; @@ -5392,19 +5434,19 @@ class PDFPresentationMode { if (contextMenuItems) { contextMenuItems.contextFirstPage.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('firstpage'); + this.eventBus.dispatch('firstpage', { source: this }); }); contextMenuItems.contextLastPage.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('lastpage'); + this.eventBus.dispatch('lastpage', { source: this }); }); contextMenuItems.contextPageRotateCw.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('rotatecw'); + this.eventBus.dispatch('rotatecw', { source: this }); }); contextMenuItems.contextPageRotateCcw.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('rotateccw'); + this.eventBus.dispatch('rotateccw', { source: this }); }); } } @@ -8457,16 +8499,16 @@ class Toolbar { let { eventBus, items } = this; let self = this; items.previous.addEventListener('click', function () { - eventBus.dispatch('previouspage'); + eventBus.dispatch('previouspage', { source: self }); }); items.next.addEventListener('click', function () { - eventBus.dispatch('nextpage'); + eventBus.dispatch('nextpage', { source: self }); }); items.zoomIn.addEventListener('click', function () { - eventBus.dispatch('zoomin'); + eventBus.dispatch('zoomin', { source: self }); }); items.zoomOut.addEventListener('click', function () { - eventBus.dispatch('zoomout'); + eventBus.dispatch('zoomout', { source: self }); }); items.pageNumber.addEventListener('click', function () { this.select(); @@ -8487,16 +8529,16 @@ class Toolbar { }); }); items.presentationModeButton.addEventListener('click', function () { - eventBus.dispatch('presentationmode'); + eventBus.dispatch('presentationmode', { source: self }); }); items.openFile.addEventListener('click', function () { - eventBus.dispatch('openfile'); + eventBus.dispatch('openfile', { source: self }); }); items.print.addEventListener('click', function () { - eventBus.dispatch('print'); + eventBus.dispatch('print', { source: self }); }); items.download.addEventListener('click', function () { - eventBus.dispatch('download'); + eventBus.dispatch('download', { source: self }); }); items.scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler; eventBus.on('localized', () => { @@ -9034,6 +9076,7 @@ function getDefaultPreferences() { "sidebarViewOnLoad": 0, "cursorToolOnLoad": 0, "enableWebGL": false, + "eventBusDispatchToDOM": false, "pdfBugEnabled": false, "disableRange": false, "disableStream": false, diff --git a/browser/extensions/pdfjs/moz.yaml b/browser/extensions/pdfjs/moz.yaml index d1eeff1ffcfe..152fed75c274 100644 --- a/browser/extensions/pdfjs/moz.yaml +++ b/browser/extensions/pdfjs/moz.yaml @@ -20,7 +20,7 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: version 2.0.775 + release: version 2.0.813 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ From d7274895ea0aad10c88a040ce1884b57d1179229 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 3 Sep 2018 21:49:18 -0400 Subject: [PATCH 30/80] Bug 1488306 - Remove the XPCOM component registration for nsUnknwonDecoder; r=valentin Differential Revision: https://phabricator.services.mozilla.com/D4897 --- netwerk/base/nsBaseChannel.cpp | 7 ++----- netwerk/build/nsNetCID.h | 8 -------- netwerk/build/nsNetModule.cpp | 1 - netwerk/streamconv/converters/moz.build | 4 ++++ 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/netwerk/base/nsBaseChannel.cpp b/netwerk/base/nsBaseChannel.cpp index 1a50a8e589f7..d9e0d6466328 100644 --- a/netwerk/base/nsBaseChannel.cpp +++ b/netwerk/base/nsBaseChannel.cpp @@ -9,7 +9,7 @@ #include "nsURLHelper.h" #include "nsNetCID.h" #include "nsMimeTypes.h" -#include "nsIContentSniffer.h" +#include "nsUnknownDecoder.h" #include "nsIScriptSecurityManager.h" #include "nsMimeTypes.h" #include "nsIHttpChannel.h" @@ -824,10 +824,7 @@ CallUnknownTypeSniffer(void *aClosure, const uint8_t *aData, uint32_t aCount) { nsIChannel *chan = static_cast(aClosure); - nsCOMPtr sniffer = - do_CreateInstance(NS_GENERIC_CONTENT_SNIFFER); - if (!sniffer) - return; + RefPtr sniffer = new nsUnknownDecoder(); nsAutoCString detected; nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected); diff --git a/netwerk/build/nsNetCID.h b/netwerk/build/nsNetCID.h index ffb762c37d4b..0e28c790165a 100644 --- a/netwerk/build/nsNetCID.h +++ b/netwerk/build/nsNetCID.h @@ -952,14 +952,6 @@ {0xa1, 0x6c, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \ } -/** - * General-purpose content sniffer component. Use with CreateInstance. - * - * Implements nsIContentSniffer - */ -#define NS_GENERIC_CONTENT_SNIFFER \ - "@mozilla.org/network/content-sniffer;1" - /** * Detector that can act as either an nsIStreamConverter or an * nsIContentSniffer to decide whether text/plain data is "really" text/plain diff --git a/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 5d3b1369e525..a2ba8dac5991 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/netwerk/build/nsNetModule.cpp @@ -948,7 +948,6 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = { { NS_ISTREAMCONVERTER_KEY MULTI_BYTERANGES, &kNS_MULTIMIXEDCONVERTER_CID }, { NS_ISTREAMCONVERTER_KEY MULTI_MIXED, &kNS_MULTIMIXEDCONVERTER_CID }, { NS_ISTREAMCONVERTER_KEY UNKNOWN_CONTENT, &kNS_UNKNOWNDECODER_CID }, - { NS_GENERIC_CONTENT_SNIFFER, &kNS_UNKNOWNDECODER_CID }, { NS_BINARYDETECTOR_CONTRACTID, &kNS_BINARYDETECTOR_CID }, { NS_ISTREAMCONVERTER_KEY GZIP_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID }, { NS_ISTREAMCONVERTER_KEY XGZIP_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID }, diff --git a/netwerk/streamconv/converters/moz.build b/netwerk/streamconv/converters/moz.build index 17d6c96748c6..451d1cf3f851 100644 --- a/netwerk/streamconv/converters/moz.build +++ b/netwerk/streamconv/converters/moz.build @@ -8,6 +8,10 @@ XPIDL_SOURCES += [ 'nsICompressConvStats.idl' ] +EXPORTS += [ + 'nsUnknownDecoder.h', +] + XPIDL_MODULE = 'necko_http' UNIFIED_SOURCES += [ From 487b897985237bf1f7eccca1e51a287e2542e615 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 3 Sep 2018 15:20:20 -0400 Subject: [PATCH 31/80] Bug 1488266 - Use const nsACString& in the argument to ToUTF8() in nsMIMEHeaderParamImpl.cpp; r=hsivonen Differential Revision: https://phabricator.services.mozilla.com/D4886 --- netwerk/mime/nsMIMEHeaderParamImpl.cpp | 74 +++++++++++++------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/netwerk/mime/nsMIMEHeaderParamImpl.cpp b/netwerk/mime/nsMIMEHeaderParamImpl.cpp index e4ad8241775d..fe81362784c1 100644 --- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp +++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp @@ -26,22 +26,22 @@ using mozilla::Encoding; static char *DecodeQ(const char *, uint32_t); static bool Is7bitNonAsciiString(const char *, uint32_t); -static void CopyRawHeader(const char *, uint32_t, const char *, nsACString &); -static nsresult DecodeRFC2047Str(const char *, const char *, bool, nsACString&); -static nsresult internalDecodeParameter(const nsACString&, const char*, - const char*, bool, bool, nsACString&); +static void CopyRawHeader(const char *, uint32_t, const nsACString&, nsACString &); +static nsresult DecodeRFC2047Str(const char *, const nsACString&, bool, nsACString&); +static nsresult internalDecodeParameter(const nsACString&, const nsACString&, + const nsACString&, bool, bool, nsACString&); static nsresult ToUTF8(const nsACString& aString, - const char* aCharset, + const nsACString& aCharset, bool aAllowSubstitution, nsACString& aResult) { - if (!aCharset || !*aCharset) + if (aCharset.IsEmpty()) { return NS_ERROR_INVALID_ARG; + } - auto encoding = Encoding::ForLabelNoReplacement( - mozilla::MakeStringSpan(aCharset)); + auto encoding = Encoding::ForLabelNoReplacement(aCharset); if (!encoding) { return NS_ERROR_UCONV_NOCONV; } @@ -58,7 +58,7 @@ ToUTF8(const nsACString& aString, static nsresult ConvertStringToUTF8(const nsACString& aString, - const char* aCharset, + const nsACString& aCharset, bool aSkipCheck, bool aAllowSubstitution, nsACString& aUTF8String) @@ -161,7 +161,7 @@ nsMIMEHeaderParamImpl::DoGetParameter(const nsACString& aHeaderVal, // if necessary. nsAutoCString str1; - rv = internalDecodeParameter(med, charset.get(), nullptr, false, + rv = internalDecodeParameter(med, charset, EmptyCString(), false, // was aDecoding == MIME_FIELD_ENCODING // see bug 875615 true, @@ -172,8 +172,7 @@ nsMIMEHeaderParamImpl::DoGetParameter(const nsACString& aHeaderVal, { const Encoding* encoding = Encoding::ForLabel(aFallbackCharset); nsAutoCString str2; - if (NS_SUCCEEDED(ConvertStringToUTF8(str1, - PromiseFlatCString(aFallbackCharset).get(), false, + if (NS_SUCCEEDED(ConvertStringToUTF8(str1, aFallbackCharset, false, encoding != UTF_8_ENCODING, str2))) { CopyUTF8toUTF16(str2, aResult); @@ -372,14 +371,13 @@ int32_t parseSegmentNumber(const char *aValue, int32_t aLen) // validate a given octet sequence for compliance with the specified // encoding -bool IsValidOctetSequenceForCharset(nsACString& aCharset, const char *aOctets) +bool IsValidOctetSequenceForCharset(const nsACString& aCharset, const char *aOctets) { nsAutoCString tmpRaw; tmpRaw.Assign(aOctets); nsAutoCString tmpDecoded; - nsresult rv = ConvertStringToUTF8(tmpRaw, - PromiseFlatCString(aCharset).get(), + nsresult rv = ConvertStringToUTF8(tmpRaw, aCharset, false, false, tmpDecoded); if (rv != NS_OK) { @@ -780,7 +778,7 @@ increment_str: } nsresult -internalDecodeRFC2047Header(const char* aHeaderVal, const char* aDefaultCharset, +internalDecodeRFC2047Header(const char* aHeaderVal, const nsACString& aDefaultCharset, bool aOverrideCharset, bool aEatContinuations, nsACString& aResult) { @@ -795,7 +793,7 @@ internalDecodeRFC2047Header(const char* aHeaderVal, const char* aDefaultCharset, // aDefaultCharset is specified, decodes RFC 2047 encoding and converts // to UTF-8. Otherwise, just strips away CRLF. if (PL_strstr(aHeaderVal, "=?") || - (aDefaultCharset && (!IsUTF8(nsDependentCString(aHeaderVal)) || + (!aDefaultCharset.IsEmpty() && (!IsUTF8(nsDependentCString(aHeaderVal)) || Is7bitNonAsciiString(aHeaderVal, strlen(aHeaderVal))))) { DecodeRFC2047Str(aHeaderVal, aDefaultCharset, aOverrideCharset, aResult); } else if (aEatContinuations && @@ -824,7 +822,8 @@ nsMIMEHeaderParamImpl::DecodeRFC2047Header(const char* aHeaderVal, bool aEatContinuations, nsACString& aResult) { - return internalDecodeRFC2047Header(aHeaderVal, aDefaultCharset, + return internalDecodeRFC2047Header(aHeaderVal, + nsCString(aDefaultCharset), aOverrideCharset, aEatContinuations, aResult); } @@ -933,7 +932,7 @@ nsMIMEHeaderParamImpl::DecodeRFC5987Param(const nsACString& aParamVal, // finally convert octet sequence to UTF-8 and be done nsAutoCString utf8; - nsresult rv = ConvertStringToUTF8(value, charset.get(), true, false, utf8); + nsresult rv = ConvertStringToUTF8(value, charset, true, false, utf8); NS_ENSURE_SUCCESS(rv, rv); CopyUTF8toUTF16(utf8, aResult); @@ -941,14 +940,14 @@ nsMIMEHeaderParamImpl::DecodeRFC5987Param(const nsACString& aParamVal, } nsresult -internalDecodeParameter(const nsACString& aParamValue, const char* aCharset, - const char* aDefaultCharset, bool aOverrideCharset, +internalDecodeParameter(const nsACString& aParamValue, const nsACString& aCharset, + const nsACString& aDefaultCharset, bool aOverrideCharset, bool aDecode2047, nsACString& aResult) { aResult.Truncate(); // If aCharset is given, aParamValue was obtained from RFC2231/5987 // encoding and we're pretty sure that it's in aCharset. - if (aCharset && *aCharset) + if (!aCharset.IsEmpty()) { return ConvertStringToUTF8(aParamValue, aCharset, true, true, aResult); } @@ -997,7 +996,8 @@ nsMIMEHeaderParamImpl::DecodeParameter(const nsACString& aParamValue, bool aOverrideCharset, nsACString& aResult) { - return internalDecodeParameter(aParamValue, aCharset, aDefaultCharset, + return internalDecodeParameter(aParamValue, nsCString(aCharset), + nsCString(aDefaultCharset), aOverrideCharset, true, aResult); } @@ -1111,12 +1111,12 @@ bool Is7bitNonAsciiString(const char *input, uint32_t len) // chars. *aOutput is advanced by the number of output octets. // static void CopyRawHeader(const char *aInput, uint32_t aLen, - const char *aDefaultCharset, nsACString &aOutput) + const nsACString& aDefaultCharset, nsACString &aOutput) { int32_t c; // If aDefaultCharset is not specified, make a blind copy. - if (!aDefaultCharset || !*aDefaultCharset) { + if (aDefaultCharset.IsEmpty()) { aOutput.Append(aInput, aLen); return; } @@ -1135,14 +1135,14 @@ void CopyRawHeader(const char *aInput, uint32_t aLen, // skip ASCIIness/UTF8ness test if aInput is supected to be a 7bit non-ascii // string and aDefaultCharset is a 7bit non-ascii charset. bool skipCheck = (c == 0x1B || c == '~') && - IS_7BIT_NON_ASCII_CHARSET(aDefaultCharset); + IS_7BIT_NON_ASCII_CHARSET(PromiseFlatCString(aDefaultCharset).get()); // If not UTF-8, treat as default charset nsAutoCString utf8Text; if (NS_SUCCEEDED( ConvertStringToUTF8(Substring(aInput, aInput + aLen), - aDefaultCharset, skipCheck, true, - utf8Text))) { + PromiseFlatCString(aDefaultCharset), + skipCheck, true, utf8Text))) { aOutput.Append(utf8Text); } else { // replace each octet with Unicode replacement char in UTF-8. for (uint32_t i = 0; i < aLen; i++) { @@ -1156,7 +1156,7 @@ void CopyRawHeader(const char *aInput, uint32_t aLen, } nsresult DecodeQOrBase64Str(const char *aEncoded, size_t aLen, char aQOrBase64, - const char *aCharset, nsACString &aResult) + const nsACString& aCharset, nsACString &aResult) { char *decodedText; NS_ASSERTION(aQOrBase64 == 'Q' || aQOrBase64 == 'B', "Should be 'Q' or 'B'"); @@ -1176,7 +1176,7 @@ nsresult DecodeQOrBase64Str(const char *aEncoded, size_t aLen, char aQOrBase64, // skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset. nsresult rv = ConvertStringToUTF8(nsDependentCString(decodedText), aCharset, - IS_7BIT_NON_ASCII_CHARSET(aCharset), + IS_7BIT_NON_ASCII_CHARSET(PromiseFlatCString(aCharset).get()), true, utf8Text); free(decodedText); if (NS_FAILED(rv)) { @@ -1195,7 +1195,7 @@ static const char especials[] = R"(()<>@,;:\"/[]?.=)"; // ignored and aDefaultCharset is assumed, instead. aDefaultCharset // is also used to convert raw octets (without RFC 2047 encoding) to UTF-8. //static -nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, +nsresult DecodeRFC2047Str(const char *aHeader, const nsACString& aDefaultCharset, bool aOverrideCharset, nsACString &aResult) { const char *p, *q = nullptr, *r; @@ -1228,7 +1228,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, if (!isLastEncodedWord || q < p) { if (!encodedText.IsEmpty()) { rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), - prevEncoding, prevCharset.get(), aResult); + prevEncoding, prevCharset, aResult); if (NS_FAILED(rv)) { aResult.Append(encodedText); } @@ -1286,7 +1286,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, // Override charset if requested. Never override labeled UTF-8. // Use default charset instead of UNKNOWN-8BIT if ((aOverrideCharset && 0 != nsCRT::strcasecmp(curCharset.get(), "UTF-8")) - || (aDefaultCharset && 0 == nsCRT::strcasecmp(curCharset.get(), "UNKNOWN-8BIT")) + || (!aDefaultCharset.IsEmpty() && 0 == nsCRT::strcasecmp(curCharset.get(), "UNKNOWN-8BIT")) ) { curCharset = aDefaultCharset; } @@ -1321,7 +1321,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, bDecoded = true; } rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), - prevEncoding, prevCharset.get(), aResult); + prevEncoding, prevCharset, aResult); if (NS_FAILED(rv)) { aResult.Append(encodedText); } @@ -1331,7 +1331,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, } if (!bDecoded) { rv = DecodeQOrBase64Str(q + 2, R - (q + 2), curEncoding, - curCharset.get(), aResult); + curCharset, aResult); if (NS_FAILED(rv)) { aResult.Append(encodedText); } @@ -1344,7 +1344,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, badsyntax: if (!encodedText.IsEmpty()) { rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), - prevEncoding, prevCharset.get(), aResult); + prevEncoding, prevCharset, aResult); if (NS_FAILED(rv)) { aResult.Append(encodedText); } @@ -1359,7 +1359,7 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, if (!encodedText.IsEmpty()) { rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), - prevEncoding, prevCharset.get(), aResult); + prevEncoding, prevCharset, aResult); if (NS_FAILED(rv)) { aResult.Append(encodedText); } From 945900da3d7d9b6d163814665365b38f7ae9d8bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabrice=20Desr=C3=A9?= Date: Tue, 4 Sep 2018 10:07:38 -0400 Subject: [PATCH 32/80] Bug 1487850 - Link.cpp doesn't build if MOZ_PLACES is not defined on non-ANDROID platforms r=Ehsan --- dom/base/Link.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dom/base/Link.cpp b/dom/base/Link.cpp index e536f5c621ff..fe66e45c4409 100644 --- a/dom/base/Link.cpp +++ b/dom/base/Link.cpp @@ -9,10 +9,10 @@ #include "mozilla/EventStates.h" #include "mozilla/MemoryReporting.h" #include "mozilla/dom/Element.h" -#ifdef ANDROID -#include "mozilla/IHistory.h" -#else +#if defined(MOZ_PLACES) #include "mozilla/places/History.h" +#else +#include "mozilla/IHistory.h" #endif #include "nsIURL.h" #include "nsIURIMutator.h" @@ -35,7 +35,7 @@ namespace mozilla { namespace dom { -#ifndef ANDROID +#if defined(MOZ_PLACES) using places::History; #endif @@ -381,8 +381,10 @@ Link::LinkState() const if (mHistory && hrefURI) { #ifdef ANDROID nsCOMPtr history = services::GetHistoryService(); -#else +#elif defined(MOZ_PLACES) History* history = History::GetService(); +#else + nsCOMPtr history; #endif if (history) { nsresult rv = history->RegisterVisitedCallback(hrefURI, self); @@ -846,8 +848,10 @@ Link::UnregisterFromHistory() if (mHistory && mCachedURI) { #ifdef ANDROID nsCOMPtr history = services::GetHistoryService(); -#else +#elif defined(MOZ_PLACES) History* history = History::GetService(); +#else + nsCOMPtr history; #endif if (history) { nsresult rv = history->UnregisterVisitedCallback(mCachedURI, this); From 8038c6973e50313052f3912d2298142b6491e262 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 30 Aug 2018 01:03:36 -0400 Subject: [PATCH 33/80] Bug 1486487 - Toggle a label's control in case it's a checkbox; r=dao Differential Revision: https://phabricator.services.mozilla.com/D4833 --- toolkit/content/tests/widgets/chrome.ini | 2 + .../tests/widgets/test_label_checkbox.xul | 42 +++++++++++++++++ .../tests/widgets/window_label_checkbox.xul | 46 +++++++++++++++++++ toolkit/content/widgets/text.xml | 25 ++++++++-- 4 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 toolkit/content/tests/widgets/test_label_checkbox.xul create mode 100644 toolkit/content/tests/widgets/window_label_checkbox.xul diff --git a/toolkit/content/tests/widgets/chrome.ini b/toolkit/content/tests/widgets/chrome.ini index 531c1b525189..f0b328648504 100644 --- a/toolkit/content/tests/widgets/chrome.ini +++ b/toolkit/content/tests/widgets/chrome.ini @@ -6,6 +6,7 @@ skip-if = os == 'android' support-files = tree_shared.js popup_shared.js + window_label_checkbox.xul window_menubar.xul seek_with_sound.ogg @@ -14,6 +15,7 @@ skip-if = os == 'linux' # Bug 1116215 [test_contextmenu_menugroup.xul] skip-if = os == 'linux' # Bug 1115088 [test_editor_currentURI.xul] +[test_label_checkbox.xul] [test_menubar.xul] skip-if = os == 'mac' [test_popupanchor.xul] diff --git a/toolkit/content/tests/widgets/test_label_checkbox.xul b/toolkit/content/tests/widgets/test_label_checkbox.xul new file mode 100644 index 000000000000..f32dde415446 --- /dev/null +++ b/toolkit/content/tests/widgets/test_label_checkbox.xul @@ -0,0 +1,42 @@ + + + + + + + Label Checkbox Tests + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/window_label_checkbox.xul b/toolkit/content/tests/widgets/window_label_checkbox.xul new file mode 100644 index 000000000000..3d4164c42561 --- /dev/null +++ b/toolkit/content/tests/widgets/window_label_checkbox.xul @@ -0,0 +1,46 @@ + + + + + + + + + + + + + diff --git a/toolkit/content/widgets/text.xml b/toolkit/content/widgets/text.xml index e73cc0934099..727ecb0aef7e 100644 --- a/toolkit/content/widgets/text.xml +++ b/toolkit/content/widgets/text.xml @@ -281,11 +281,26 @@ - + From c3aabc00acafe2f3c9641db85e3df4147cbf9569 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Tue, 4 Sep 2018 00:42:00 +0300 Subject: [PATCH 34/80] Bug 1449374 - Disable prefetch-allowed.html on Win10 for frequent failures. r=gbrown --- .../prefetch-src/prefetch-allowed.html.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/web-platform/meta/content-security-policy/prefetch-src/prefetch-allowed.html.ini b/testing/web-platform/meta/content-security-policy/prefetch-src/prefetch-allowed.html.ini index 3f717ea77689..c45a4d9214c2 100644 --- a/testing/web-platform/meta/content-security-policy/prefetch-src/prefetch-allowed.html.ini +++ b/testing/web-platform/meta/content-security-policy/prefetch-src/prefetch-allowed.html.ini @@ -3,3 +3,4 @@ comment: prefetch-src is not supported via meta tag but the test is passing as the tests only tests that 'self' works disabled: if not debug and (os == "win") and (version == "6.1.7601"): https://bugzilla.mozilla.org/show_bug.cgi?id=1449374 + if (os == "win") and (version == "10.0.15603") and (bits == 64): https://bugzilla.mozilla.org/show_bug.cgi?id=1449374 From b5f0a96ffffff9db72b014468ac89fa3cc152c3f Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 4 Sep 2018 10:40:42 -0400 Subject: [PATCH 35/80] Bug 1440879 - Emit source-like generated files into generated-sources.json. r=froydnj --- python/mozbuild/mozbuild/backend/common.py | 9 +++++++++ python/mozbuild/mozbuild/frontend/data.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py index 949bbee30eb8..25f96113a683 100644 --- a/python/mozbuild/mozbuild/backend/common.py +++ b/python/mozbuild/mozbuild/backend/common.py @@ -28,6 +28,7 @@ from mozbuild.frontend.data import ( Exports, FinalTargetPreprocessedFiles, FinalTargetFiles, + GeneratedFile, GeneratedSources, GnProjectData, HostLibrary, @@ -169,6 +170,14 @@ class CommonBackend(BuildBackend): self._handle_generated_sources(obj.files) return False + elif isinstance(obj, GeneratedFile): + if obj.required_for_compile: + for f in obj.required_for_compile: + fullpath = ObjDirPath(obj._context, '!' + f).full_path + relpath = mozpath.relpath(fullpath, obj._context.config.topobjdir) + self._handle_generated_sources([relpath]) + return False + elif isinstance(obj, Exports): objdir_files = [f.full_path for path, files in obj.files.walk() for f in files if isinstance(f, ObjDirPath)] if objdir_files: diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index 6bdf7ce543ce..43daa343faa4 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -1170,7 +1170,7 @@ class GeneratedFile(ContextDerived): '.rs', 'new', # 'new' is an output from make-stl-wrappers.py ) - self.required_for_compile = any(f.endswith(suffixes) for f in self.outputs) + self.required_for_compile = [f for f in self.outputs if f.endswith(suffixes)] class ChromeManifestEntry(ContextDerived): From 1a1ca59f9a1a707b850acd323aa61dde0a528a22 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 4 Sep 2018 10:40:45 -0400 Subject: [PATCH 36/80] Bug 1440879 - Ensure all the stl_wrappers end up in the generated-files tarball. r=froydnj --- config/moz.build | 4 ++++ python/mozbuild/mozbuild/frontend/data.py | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config/moz.build b/config/moz.build index d9c28fe54d05..ce6297393373 100644 --- a/config/moz.build +++ b/config/moz.build @@ -47,6 +47,10 @@ if CONFIG['WRAP_STL_INCLUDES']: stl_compiler = 'msvc' if stl_compiler: + # Note that the 'stl_wrappers' folder is known to the build system as + # containing generated files; if this is changed here then the code in + # GeneratedFile.__init__ in python/mozbuild/mozbuild/frontend/data.py + # might need to be updated accordingly as well. template_file = SRCDIR + '/%s-stl-wrapper.template.h' % stl_compiler output_dir = '../dist/stl_wrappers' # We have to use a sentinel file as the first file because the diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index 43daa343faa4..b737b5ea2e1f 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -1168,9 +1168,8 @@ class GeneratedFile(ContextDerived): '.inc', '.py', '.rs', - 'new', # 'new' is an output from make-stl-wrappers.py ) - self.required_for_compile = [f for f in self.outputs if f.endswith(suffixes)] + self.required_for_compile = [f for f in self.outputs if f.endswith(suffixes) or 'stl_wrappers/' in f] class ChromeManifestEntry(ContextDerived): From 6b3e97f314a81623e5f98dc8cd62da3e94bcef15 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Tue, 4 Sep 2018 10:47:41 -0400 Subject: [PATCH 37/80] Bug 1488114 - Refactor the reducers in RDM. r=rcaliman --- .../locales/en-US/responsive.properties | 7 ++--- .../client/responsive.html/actions/devices.js | 3 +- .../actions/display-pixel-ratio.js | 23 -------------- .../client/responsive.html/actions/index.js | 12 +++---- .../responsive.html/actions/location.js | 22 ------------- .../client/responsive.html/actions/moz.build | 3 -- .../actions/reload-conditions.js | 3 +- .../responsive.html/actions/screenshot.js | 3 +- .../actions/touch-simulation.js | 22 ------------- devtools/client/responsive.html/actions/ui.js | 21 +++++++++++++ .../client/responsive.html/browser/swap.js | 2 +- .../responsive.html/browser/web-navigation.js | 1 + .../client/responsive.html/components/App.js | 22 ++++++------- .../components/DevicePixelRatioMenu.js | 10 +++--- .../components/ResizableViewport.js | 4 +-- .../responsive.html/components/Toolbar.js | 16 +++++----- .../components/ViewportDimension.js | 4 +-- .../responsive.html/components/Viewports.js | 6 ++-- devtools/client/responsive.html/index.js | 4 +-- devtools/client/responsive.html/manager.js | 5 ++- devtools/client/responsive.html/reducers.js | 3 -- .../responsive.html/reducers/devices.js | 4 +-- .../reducers/display-pixel-ratio.js | 26 ---------------- .../responsive.html/reducers/location.js | 25 --------------- .../client/responsive.html/reducers/moz.build | 3 -- .../responsive.html/reducers/screenshot.js | 4 ++- .../reducers/touch-simulation.js | 31 ------------------- .../client/responsive.html/reducers/ui.js | 18 +++++++++++ .../responsive.html/reducers/viewports.js | 8 ++--- .../unit/test_change_display_pixel_ratio.js | 4 +-- .../test/unit/test_change_location.js | 22 ------------- .../test_update_touch_simulation_enabled.js | 6 ++-- .../responsive.html/test/unit/xpcshell.ini | 1 - devtools/client/responsive.html/types.js | 17 +--------- 34 files changed, 101 insertions(+), 264 deletions(-) delete mode 100644 devtools/client/responsive.html/actions/display-pixel-ratio.js delete mode 100644 devtools/client/responsive.html/actions/location.js delete mode 100644 devtools/client/responsive.html/actions/touch-simulation.js delete mode 100644 devtools/client/responsive.html/reducers/display-pixel-ratio.js delete mode 100644 devtools/client/responsive.html/reducers/location.js delete mode 100644 devtools/client/responsive.html/reducers/touch-simulation.js delete mode 100644 devtools/client/responsive.html/test/unit/test_change_location.js diff --git a/devtools/client/locales/en-US/responsive.properties b/devtools/client/locales/en-US/responsive.properties index 6e2ede4ee46c..aaa9c524a8d1 100644 --- a/devtools/client/locales/en-US/responsive.properties +++ b/devtools/client/locales/en-US/responsive.properties @@ -124,10 +124,9 @@ responsive.reloadConditions.touchSimulation=Reload when touch simulation is togg # to select whether to reload when user agent is changed. responsive.reloadConditions.userAgent=Reload when user agent is changed -# LOCALIZATION NOTE (responsive.reloadNotification.description): Text in notification bar -# shown on first open to clarify that some features need a reload to apply. %1$S is the -# label on the reload conditions menu (responsive.reloadConditions.label). -responsive.reloadNotification.description=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the “%1$S” menu. +# LOCALIZATION NOTE (responsive.reloadNotification.description2): Text in notification bar +# shown on first open to clarify that some features need a reload to apply. +responsive.reloadNotification.description2=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the Settings menu. # LOCALIZATION NOTE (responsive.leftAlignViewport): Label on checkbox used in the settings # menu. diff --git a/devtools/client/responsive.html/actions/devices.js b/devtools/client/responsive.html/actions/devices.js index 13a8fc4ccb05..0726596d95eb 100644 --- a/devtools/client/responsive.html/actions/devices.js +++ b/devtools/client/responsive.html/actions/devices.js @@ -4,6 +4,8 @@ "use strict"; +const Services = require("Services"); + const { ADD_DEVICE, ADD_DEVICE_TYPE, @@ -18,7 +20,6 @@ const { removeDeviceAssociation } = require("./viewports"); const { addDevice, getDevices, removeDevice } = require("devtools/client/shared/devices"); -const Services = require("Services"); const DISPLAYED_DEVICES_PREF = "devtools.responsive.html.displayedDeviceList"; /** diff --git a/devtools/client/responsive.html/actions/display-pixel-ratio.js b/devtools/client/responsive.html/actions/display-pixel-ratio.js deleted file mode 100644 index ff3343bb5d02..000000000000 --- a/devtools/client/responsive.html/actions/display-pixel-ratio.js +++ /dev/null @@ -1,23 +0,0 @@ -/* 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 { CHANGE_DISPLAY_PIXEL_RATIO } = require("./index"); - -module.exports = { - - /** - * The pixel ratio of the display has changed. This may be triggered by the user - * when changing the monitor resolution, or when the window is dragged to a different - * display with a different pixel ratio. - */ - changeDisplayPixelRatio(displayPixelRatio) { - return { - type: CHANGE_DISPLAY_PIXEL_RATIO, - displayPixelRatio, - }; - }, - -}; diff --git a/devtools/client/responsive.html/actions/index.js b/devtools/client/responsive.html/actions/index.js index 0db4d70e1254..5306161dd6f1 100644 --- a/devtools/client/responsive.html/actions/index.js +++ b/devtools/client/responsive.html/actions/index.js @@ -4,9 +4,9 @@ "use strict"; -// This file lists all of the actions available in responsive design. This +// This file lists all of the actions available in responsive design. This // central list of constants makes it easy to see all possible action names at -// a glance. Please add a comment with each new action type. +// a glance. Please add a comment with each new action type. const { createEnum } = require("devtools/client/shared/enum"); @@ -28,7 +28,7 @@ createEnum([ // Change the device displayed in the viewport. "CHANGE_DEVICE", - // Change the location of the page. This may be triggered by the user + // Change the location of the page. This may be triggered by the user // directly entering a new URL, navigating with links, etc. "CHANGE_LOCATION", @@ -48,9 +48,6 @@ createEnum([ // Change one of the reload conditions. "CHANGE_RELOAD_CONDITION", - // Change the touch simulation state. - "CHANGE_TOUCH_SIMULATION", - // Indicates that the device list is being loaded. "LOAD_DEVICE_LIST_START", @@ -84,6 +81,9 @@ createEnum([ // Toggles the left alignment of the viewports. "TOGGLE_LEFT_ALIGNMENT", + // Toggles the touch simulation state of the viewports. + "TOGGLE_TOUCH_SIMULATION", + // Update the device display state in the device selector. "UPDATE_DEVICE_DISPLAYED", diff --git a/devtools/client/responsive.html/actions/location.js b/devtools/client/responsive.html/actions/location.js deleted file mode 100644 index 565825e5e655..000000000000 --- a/devtools/client/responsive.html/actions/location.js +++ /dev/null @@ -1,22 +0,0 @@ -/* 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 { CHANGE_LOCATION } = require("./index"); - -module.exports = { - - /** - * The location of the page has changed. This may be triggered by the user - * directly entering a new URL, navigating with links, etc. - */ - changeLocation(location) { - return { - type: CHANGE_LOCATION, - location, - }; - }, - -}; diff --git a/devtools/client/responsive.html/actions/moz.build b/devtools/client/responsive.html/actions/moz.build index 26e34ff8b0da..ae665ef2348b 100644 --- a/devtools/client/responsive.html/actions/moz.build +++ b/devtools/client/responsive.html/actions/moz.build @@ -6,12 +6,9 @@ DevToolsModules( 'devices.js', - 'display-pixel-ratio.js', 'index.js', - 'location.js', 'reload-conditions.js', 'screenshot.js', - 'touch-simulation.js', 'ui.js', 'viewports.js', ) diff --git a/devtools/client/responsive.html/actions/reload-conditions.js b/devtools/client/responsive.html/actions/reload-conditions.js index 732f8a738166..22485a14e98f 100644 --- a/devtools/client/responsive.html/actions/reload-conditions.js +++ b/devtools/client/responsive.html/actions/reload-conditions.js @@ -4,13 +4,14 @@ "use strict"; +const Services = require("Services"); + const { CHANGE_RELOAD_CONDITION, LOAD_RELOAD_CONDITIONS_END, } = require("./index"); const Types = require("../types"); -const Services = require("Services"); const PREF_PREFIX = "devtools.responsive.reloadConditions."; diff --git a/devtools/client/responsive.html/actions/screenshot.js b/devtools/client/responsive.html/actions/screenshot.js index 482eff85b8c1..317ae23e00a1 100644 --- a/devtools/client/responsive.html/actions/screenshot.js +++ b/devtools/client/responsive.html/actions/screenshot.js @@ -6,6 +6,8 @@ "use strict"; +const Services = require("Services"); + const { TAKE_SCREENSHOT_START, TAKE_SCREENSHOT_END, @@ -14,7 +16,6 @@ const { const { getFormatStr } = require("../utils/l10n"); const { getTopLevelWindow } = require("../utils/window"); const e10s = require("../utils/e10s"); -const Services = require("Services"); const CAMERA_AUDIO_URL = "resource://devtools/client/themes/audio/shutter.wav"; diff --git a/devtools/client/responsive.html/actions/touch-simulation.js b/devtools/client/responsive.html/actions/touch-simulation.js deleted file mode 100644 index 8f98101e7a78..000000000000 --- a/devtools/client/responsive.html/actions/touch-simulation.js +++ /dev/null @@ -1,22 +0,0 @@ -/* 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/. */ - -/* eslint-env browser */ - -"use strict"; - -const { - CHANGE_TOUCH_SIMULATION -} = require("./index"); - -module.exports = { - - changeTouchSimulation(enabled) { - return { - type: CHANGE_TOUCH_SIMULATION, - enabled, - }; - }, - -}; diff --git a/devtools/client/responsive.html/actions/ui.js b/devtools/client/responsive.html/actions/ui.js index 22399f294290..95abe2bf3c1b 100644 --- a/devtools/client/responsive.html/actions/ui.js +++ b/devtools/client/responsive.html/actions/ui.js @@ -5,11 +5,25 @@ "use strict"; const { + CHANGE_DISPLAY_PIXEL_RATIO, TOGGLE_LEFT_ALIGNMENT, + TOGGLE_TOUCH_SIMULATION, } = require("./index"); module.exports = { + /** + * The pixel ratio of the display has changed. This may be triggered by the user + * when changing the monitor resolution, or when the window is dragged to a different + * display with a different pixel ratio. + */ + changeDisplayPixelRatio(displayPixelRatio) { + return { + type: CHANGE_DISPLAY_PIXEL_RATIO, + displayPixelRatio, + }; + }, + toggleLeftAlignment(enabled) { return { type: TOGGLE_LEFT_ALIGNMENT, @@ -17,4 +31,11 @@ module.exports = { }; }, + toggleTouchSimulation(enabled) { + return { + type: TOGGLE_TOUCH_SIMULATION, + enabled, + }; + }, + }; diff --git a/devtools/client/responsive.html/browser/swap.js b/devtools/client/responsive.html/browser/swap.js index 3287ce743426..b3d79701110f 100644 --- a/devtools/client/responsive.html/browser/swap.js +++ b/devtools/client/responsive.html/browser/swap.js @@ -5,9 +5,9 @@ "use strict"; const { Ci } = require("chrome"); +const Services = require("Services"); const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm"); const { tunnelToInnerBrowser } = require("./tunnel"); -const Services = require("Services"); function debug(msg) { // console.log(`RDM swap: ${msg}`); diff --git a/devtools/client/responsive.html/browser/web-navigation.js b/devtools/client/responsive.html/browser/web-navigation.js index f28f26ce9b6b..c82973201d09 100644 --- a/devtools/client/responsive.html/browser/web-navigation.js +++ b/devtools/client/responsive.html/browser/web-navigation.js @@ -10,6 +10,7 @@ const Services = require("Services"); const { NetUtil } = require("resource://gre/modules/NetUtil.jsm"); const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm"); const Telemetry = require("devtools/client/shared/telemetry"); + const telemetry = new Telemetry(); function readInputStreamToString(stream) { diff --git a/devtools/client/responsive.html/components/App.js b/devtools/client/responsive.html/components/App.js index e25a26fbef61..d4413a8f8f2d 100644 --- a/devtools/client/responsive.html/components/App.js +++ b/devtools/client/responsive.html/components/App.js @@ -6,7 +6,7 @@ "use strict"; -const { Component, createFactory } = require("devtools/client/shared/vendor/react"); +const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect } = require("devtools/client/shared/vendor/react-redux"); @@ -27,8 +27,10 @@ const { } = require("../actions/devices"); const { changeReloadCondition } = require("../actions/reload-conditions"); const { takeScreenshot } = require("../actions/screenshot"); -const { changeTouchSimulation } = require("../actions/touch-simulation"); -const { toggleLeftAlignment } = require("../actions/ui"); +const { + toggleTouchSimulation, + toggleLeftAlignment, +} = require("../actions/ui"); const { changeDevice, changePixelRatio, @@ -39,16 +41,14 @@ const { const Types = require("../types"); -class App extends Component { +class App extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, dispatch: PropTypes.func.isRequired, - displayPixelRatio: Types.pixelRatio.value.isRequired, networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired, reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired, screenshot: PropTypes.shape(Types.screenshot).isRequired, - touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired, viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired, }; } @@ -93,7 +93,7 @@ class App extends Component { device, }, "*"); this.props.dispatch(changeDevice(id, device.name, deviceType)); - this.props.dispatch(changeTouchSimulation(device.touch)); + this.props.dispatch(toggleTouchSimulation(device.touch)); this.props.dispatch(changePixelRatio(id, device.pixelRatio)); } @@ -123,7 +123,7 @@ class App extends Component { type: "change-touch-simulation", enabled, }, "*"); - this.props.dispatch(changeTouchSimulation(enabled)); + this.props.dispatch(toggleTouchSimulation(enabled)); } onContentResize({ width, height }) { @@ -150,7 +150,7 @@ class App extends Component { // TODO: Bug 1332754: Move messaging and logic into the action creator so that device // property changes are sent from there instead of this function. this.props.dispatch(removeDeviceAssociation(id)); - this.props.dispatch(changeTouchSimulation(false)); + this.props.dispatch(toggleTouchSimulation(false)); this.props.dispatch(changePixelRatio(id, 0)); } @@ -181,11 +181,9 @@ class App extends Component { render() { const { devices, - displayPixelRatio, networkThrottling, reloadConditions, screenshot, - touchSimulation, viewports, } = this.props; @@ -226,13 +224,11 @@ class App extends Component { dom.div({ id: "app" }, Toolbar({ devices, - displayPixelRatio, networkThrottling, reloadConditions, screenshot, selectedDevice, selectedPixelRatio, - touchSimulation, viewport: viewports[0], onChangeDevice, onChangeNetworkThrottling, diff --git a/devtools/client/responsive.html/components/DevicePixelRatioMenu.js b/devtools/client/responsive.html/components/DevicePixelRatioMenu.js index 75fa97d553e5..473e6c65d235 100644 --- a/devtools/client/responsive.html/components/DevicePixelRatioMenu.js +++ b/devtools/client/responsive.html/components/DevicePixelRatioMenu.js @@ -21,10 +21,10 @@ class DevicePixelRatioMenu extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, - displayPixelRatio: Types.pixelRatio.value.isRequired, + displayPixelRatio: PropTypes.number.isRequired, onChangePixelRatio: PropTypes.func.isRequired, selectedDevice: PropTypes.string.isRequired, - selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired, + selectedPixelRatio: PropTypes.number.isRequired, }; } @@ -44,8 +44,8 @@ class DevicePixelRatioMenu extends PureComponent { return { label: getFormatStr("responsive.devicePixelRatioOption", value), type: "checkbox", - checked: selectedPixelRatio.value > 0 ? - selectedPixelRatio.value === value : + checked: selectedPixelRatio > 0 ? + selectedPixelRatio === value : displayPixelRatio === value, click: () => onChangePixelRatio(+value), }; @@ -86,7 +86,7 @@ class DevicePixelRatioMenu extends PureComponent { }, dom.span({ className: "title" }, getFormatStr("responsive.devicePixelRatioOption", - selectedPixelRatio.value || displayPixelRatio) + selectedPixelRatio || displayPixelRatio) ) ) ); diff --git a/devtools/client/responsive.html/components/ResizableViewport.js b/devtools/client/responsive.html/components/ResizableViewport.js index eefcf5c72206..22120938990c 100644 --- a/devtools/client/responsive.html/components/ResizableViewport.js +++ b/devtools/client/responsive.html/components/ResizableViewport.js @@ -6,7 +6,7 @@ "use strict"; -const { Component, createFactory } = require("devtools/client/shared/vendor/react"); +const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); @@ -18,7 +18,7 @@ const Types = require("../types"); const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION; const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION; -class ResizableViewport extends Component { +class ResizableViewport extends PureComponent { static get propTypes() { return { leftAlignmentEnabled: PropTypes.bool.isRequired, diff --git a/devtools/client/responsive.html/components/Toolbar.js b/devtools/client/responsive.html/components/Toolbar.js index b50162302872..ce50e0cec769 100644 --- a/devtools/client/responsive.html/components/Toolbar.js +++ b/devtools/client/responsive.html/components/Toolbar.js @@ -22,7 +22,7 @@ class Toolbar extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, - displayPixelRatio: Types.pixelRatio.value.isRequired, + displayPixelRatio: PropTypes.number.isRequired, leftAlignmentEnabled: PropTypes.bool.isRequired, networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired, onChangeDevice: PropTypes.func.isRequired, @@ -40,8 +40,8 @@ class Toolbar extends PureComponent { reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired, screenshot: PropTypes.shape(Types.screenshot).isRequired, selectedDevice: PropTypes.string.isRequired, - selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired, - touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired, + selectedPixelRatio: PropTypes.number.isRequired, + touchSimulationEnabled: PropTypes.bool.isRequired, viewport: PropTypes.shape(Types.viewport).isRequired, }; } @@ -68,7 +68,7 @@ class Toolbar extends PureComponent { screenshot, selectedDevice, selectedPixelRatio, - touchSimulation, + touchSimulationEnabled, viewport, } = this.props; @@ -121,10 +121,10 @@ class Toolbar extends PureComponent { dom.button({ id: "touch-simulation-button", className: "devtools-button" + - (touchSimulation.enabled ? " checked" : ""), - title: (touchSimulation.enabled ? + (touchSimulationEnabled ? " checked" : ""), + title: (touchSimulationEnabled ? getStr("responsive.disableTouch") : getStr("responsive.enableTouch")), - onClick: () => onChangeTouchSimulation(!touchSimulation.enabled), + onClick: () => onChangeTouchSimulation(!touchSimulationEnabled), }) ), dom.div( @@ -156,7 +156,9 @@ class Toolbar extends PureComponent { const mapStateToProps = state => { return { + displayPixelRatio: state.ui.displayPixelRatio, leftAlignmentEnabled: state.ui.leftAlignmentEnabled, + touchSimulationEnabled: state.ui.touchSimulationEnabled, }; }; diff --git a/devtools/client/responsive.html/components/ViewportDimension.js b/devtools/client/responsive.html/components/ViewportDimension.js index 6283427f82ac..f21576bbd363 100644 --- a/devtools/client/responsive.html/components/ViewportDimension.js +++ b/devtools/client/responsive.html/components/ViewportDimension.js @@ -4,7 +4,7 @@ "use strict"; -const { Component } = require("devtools/client/shared/vendor/react"); +const { PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); @@ -12,7 +12,7 @@ const { isKeyIn } = require("../utils/key"); const { MIN_VIEWPORT_DIMENSION } = require("../constants"); const Types = require("../types"); -class ViewportDimension extends Component { +class ViewportDimension extends PureComponent { static get propTypes() { return { onResizeViewport: PropTypes.func.isRequired, diff --git a/devtools/client/responsive.html/components/Viewports.js b/devtools/client/responsive.html/components/Viewports.js index 18aca2230417..dcdb3bb0ae6e 100644 --- a/devtools/client/responsive.html/components/Viewports.js +++ b/devtools/client/responsive.html/components/Viewports.js @@ -4,16 +4,16 @@ "use strict"; -const { connect } = require("devtools/client/shared/vendor/react-redux"); -const { Component, createFactory } = require("devtools/client/shared/vendor/react"); +const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); const ResizableViewport = createFactory(require("./ResizableViewport")); const Types = require("../types"); -class Viewports extends Component { +class Viewports extends PureComponent { static get propTypes() { return { leftAlignmentEnabled: PropTypes.bool.isRequired, diff --git a/devtools/client/responsive.html/index.js b/devtools/client/responsive.html/index.js index a4207182b17c..7248f8b7638b 100644 --- a/devtools/client/responsive.html/index.js +++ b/devtools/client/responsive.html/index.js @@ -23,10 +23,9 @@ const message = require("./utils/message"); const App = createFactory(require("./components/App")); const Store = require("./store"); const { loadDevices } = require("./actions/devices"); -const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio"); -const { changeLocation } = require("./actions/location"); const { loadReloadConditions } = require("./actions/reload-conditions"); const { addViewport, resizeViewport } = require("./actions/viewports"); +const { changeDisplayPixelRatio } = require("./actions/ui"); // Exposed for use by tests window.require = require; @@ -117,7 +116,6 @@ function onDevicePixelRatioChange() { window.addInitialViewport = ({ uri, userContextId }) => { try { onDevicePixelRatioChange(); - bootstrap.dispatch(changeLocation(uri)); bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio)); bootstrap.dispatch(addViewport(userContextId)); } catch (e) { diff --git a/devtools/client/responsive.html/manager.js b/devtools/client/responsive.html/manager.js index 931a619f64df..df5d6f5909e9 100644 --- a/devtools/client/responsive.html/manager.js +++ b/devtools/client/responsive.html/manager.js @@ -491,8 +491,7 @@ ResponsiveUI.prototype = { showReloadNotification() { if (Services.prefs.getBoolPref(RELOAD_NOTIFICATION_PREF, false)) { showNotification(this.browserWindow, this.tab, { - msg: l10n.getFormatStr("responsive.reloadNotification.description", - l10n.getStr("responsive.reloadConditions.label")), + msg: l10n.getFormatStr("responsive.reloadNotification.description2"), }); Services.prefs.setBoolPref(RELOAD_NOTIFICATION_PREF, false); } @@ -581,7 +580,7 @@ ResponsiveUI.prototype = { async onChangeTouchSimulation(event) { const { enabled } = event.data; const reloadNeeded = await this.updateTouchSimulation(enabled) && - this.reloadOnChange("touchSimulation"); + this.reloadOnChange("touchSimulation"); if (reloadNeeded) { this.getViewportBrowser().reload(); } diff --git a/devtools/client/responsive.html/reducers.js b/devtools/client/responsive.html/reducers.js index f4f36d11db1d..e8fe16089eeb 100644 --- a/devtools/client/responsive.html/reducers.js +++ b/devtools/client/responsive.html/reducers.js @@ -5,11 +5,8 @@ "use strict"; exports.devices = require("./reducers/devices"); -exports.displayPixelRatio = require("./reducers/display-pixel-ratio"); -exports.location = require("./reducers/location"); exports.networkThrottling = require("devtools/client/shared/components/throttling/reducer"); exports.reloadConditions = require("./reducers/reload-conditions"); exports.screenshot = require("./reducers/screenshot"); -exports.touchSimulation = require("./reducers/touch-simulation"); exports.ui = require("./reducers/ui"); exports.viewports = require("./reducers/viewports"); diff --git a/devtools/client/responsive.html/reducers/devices.js b/devtools/client/responsive.html/reducers/devices.js index d42251d3bdb6..45544e8cfae4 100644 --- a/devtools/client/responsive.html/reducers/devices.js +++ b/devtools/client/responsive.html/reducers/devices.js @@ -18,10 +18,10 @@ const { const Types = require("../types"); const INITIAL_DEVICES = { - types: [], isModalOpen: false, - modalOpenedFromViewport: null, listState: Types.loadableState.INITIALIZED, + modalOpenedFromViewport: null, + types: [], }; const reducers = { diff --git a/devtools/client/responsive.html/reducers/display-pixel-ratio.js b/devtools/client/responsive.html/reducers/display-pixel-ratio.js deleted file mode 100644 index dd1a9ae715d0..000000000000 --- a/devtools/client/responsive.html/reducers/display-pixel-ratio.js +++ /dev/null @@ -1,26 +0,0 @@ -/* 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/. */ - -/* eslint-env browser */ - -"use strict"; - -const { CHANGE_DISPLAY_PIXEL_RATIO } = require("../actions/index"); -const INITIAL_DISPLAY_PIXEL_RATIO = 0; - -const reducers = { - - [CHANGE_DISPLAY_PIXEL_RATIO](_, action) { - return action.displayPixelRatio; - }, - -}; - -module.exports = function(displayPixelRatio = INITIAL_DISPLAY_PIXEL_RATIO, action) { - const reducer = reducers[action.type]; - if (!reducer) { - return displayPixelRatio; - } - return reducer(displayPixelRatio, action); -}; diff --git a/devtools/client/responsive.html/reducers/location.js b/devtools/client/responsive.html/reducers/location.js deleted file mode 100644 index 02ccfdf08d81..000000000000 --- a/devtools/client/responsive.html/reducers/location.js +++ /dev/null @@ -1,25 +0,0 @@ -/* 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 { CHANGE_LOCATION } = require("../actions/index"); - -const INITIAL_LOCATION = "about:blank"; - -const reducers = { - - [CHANGE_LOCATION](_, action) { - return action.location; - }, - -}; - -module.exports = function(location = INITIAL_LOCATION, action) { - const reducer = reducers[action.type]; - if (!reducer) { - return location; - } - return reducer(location, action); -}; diff --git a/devtools/client/responsive.html/reducers/moz.build b/devtools/client/responsive.html/reducers/moz.build index f7d191b6dadc..3f2f60d74c1b 100644 --- a/devtools/client/responsive.html/reducers/moz.build +++ b/devtools/client/responsive.html/reducers/moz.build @@ -6,11 +6,8 @@ DevToolsModules( 'devices.js', - 'display-pixel-ratio.js', - 'location.js', 'reload-conditions.js', 'screenshot.js', - 'touch-simulation.js', 'ui.js', 'viewports.js', ) diff --git a/devtools/client/responsive.html/reducers/screenshot.js b/devtools/client/responsive.html/reducers/screenshot.js index 11246f5bddac..e26380889d58 100644 --- a/devtools/client/responsive.html/reducers/screenshot.js +++ b/devtools/client/responsive.html/reducers/screenshot.js @@ -9,7 +9,9 @@ const { TAKE_SCREENSHOT_START, } = require("../actions/index"); -const INITIAL_SCREENSHOT = { isCapturing: false }; +const INITIAL_SCREENSHOT = { + isCapturing: false, +}; const reducers = { diff --git a/devtools/client/responsive.html/reducers/touch-simulation.js b/devtools/client/responsive.html/reducers/touch-simulation.js deleted file mode 100644 index 6aebaa40d914..000000000000 --- a/devtools/client/responsive.html/reducers/touch-simulation.js +++ /dev/null @@ -1,31 +0,0 @@ -/* 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 { - CHANGE_TOUCH_SIMULATION, -} = require("../actions/index"); - -const INITIAL_TOUCH_SIMULATION = { - enabled: false, -}; - -const reducers = { - - [CHANGE_TOUCH_SIMULATION](touchSimulation, { enabled }) { - return Object.assign({}, touchSimulation, { - enabled, - }); - }, - -}; - -module.exports = function(touchSimulation = INITIAL_TOUCH_SIMULATION, action) { - const reducer = reducers[action.type]; - if (!reducer) { - return touchSimulation; - } - return reducer(touchSimulation, action); -}; diff --git a/devtools/client/responsive.html/reducers/ui.js b/devtools/client/responsive.html/reducers/ui.js index 10e93e10f645..5f3c8f27ddb0 100644 --- a/devtools/client/responsive.html/reducers/ui.js +++ b/devtools/client/responsive.html/reducers/ui.js @@ -7,18 +7,30 @@ const Services = require("Services"); const { + CHANGE_DISPLAY_PIXEL_RATIO, TOGGLE_LEFT_ALIGNMENT, + TOGGLE_TOUCH_SIMULATION, } = require("../actions/index"); const LEFT_ALIGNMENT_ENABLED = "devtools.responsive.leftAlignViewport.enabled"; const INITIAL_UI = { + // The pixel ratio of the display. + displayPixelRatio: 0, // Whether or not the viewports are left aligned. leftAlignmentEnabled: Services.prefs.getBoolPref(LEFT_ALIGNMENT_ENABLED), + // Whether or not touch simulation is enabled. + touchSimulationEnabled: false, }; const reducers = { + [CHANGE_DISPLAY_PIXEL_RATIO](ui, { displayPixelRatio }) { + return Object.assign({}, ui, { + displayPixelRatio, + }); + }, + [TOGGLE_LEFT_ALIGNMENT](ui, { enabled }) { const leftAlignmentEnabled = enabled !== undefined ? enabled : !ui.leftAlignmentEnabled; @@ -30,6 +42,12 @@ const reducers = { }); }, + [TOGGLE_TOUCH_SIMULATION](ui, { enabled }) { + return Object.assign({}, ui, { + touchSimulationEnabled: enabled, + }); + }, + }; module.exports = function(ui = INITIAL_UI, action) { diff --git a/devtools/client/responsive.html/reducers/viewports.js b/devtools/client/responsive.html/reducers/viewports.js index 507b5610b0d3..f75ac146a28a 100644 --- a/devtools/client/responsive.html/reducers/viewports.js +++ b/devtools/client/responsive.html/reducers/viewports.js @@ -22,9 +22,7 @@ const INITIAL_VIEWPORT = { deviceType: "", width: 320, height: 480, - pixelRatio: { - value: 0, - }, + pixelRatio: 0, userContextId: 0, }; @@ -60,9 +58,7 @@ const reducers = { } return Object.assign({}, viewport, { - pixelRatio: { - value: pixelRatio - }, + pixelRatio, }); }); }, diff --git a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js index 5289ebe3a156..4e7799323242 100644 --- a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js +++ b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js @@ -5,8 +5,8 @@ // Test changing the display pixel ratio. -const { changeDisplayPixelRatio } = - require("devtools/client/responsive.html/actions/display-pixel-ratio"); +const { changeDisplayPixelRatio } = require("devtools/client/responsive.html/actions/ui"); + const NEW_PIXEL_RATIO = 5.5; add_task(async function() { diff --git a/devtools/client/responsive.html/test/unit/test_change_location.js b/devtools/client/responsive.html/test/unit/test_change_location.js deleted file mode 100644 index f8d3274550c0..000000000000 --- a/devtools/client/responsive.html/test/unit/test_change_location.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Test changing the location of the displayed page. - -const { changeLocation } = - require("devtools/client/responsive.html/actions/location"); - -const TEST_URL = "http://example.com"; - -add_task(async function() { - const store = Store(); - const { getState, dispatch } = store; - - equal(getState().location, "about:blank", - "Defaults to about:blank at startup"); - - dispatch(changeLocation(TEST_URL)); - equal(getState().location, TEST_URL, "Location changed to TEST_URL"); -}); diff --git a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js index 12ab4e2bcf61..63503250db4a 100644 --- a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js +++ b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js @@ -5,9 +5,7 @@ // Test updating the touch simulation `enabled` property -const { - changeTouchSimulation, -} = require("devtools/client/responsive.html/actions/touch-simulation"); +const { toggleTouchSimulation } = require("devtools/client/responsive.html/actions/touch-simulation"); add_task(async function() { const store = Store(); @@ -16,7 +14,7 @@ add_task(async function() { ok(!getState().touchSimulation.enabled, "Touch simulation is disabled by default."); - dispatch(changeTouchSimulation(true)); + dispatch(toggleTouchSimulation(true)); ok(getState().touchSimulation.enabled, "Touch simulation is enabled."); diff --git a/devtools/client/responsive.html/test/unit/xpcshell.ini b/devtools/client/responsive.html/test/unit/xpcshell.ini index 432e68ed2030..b5241660f4c0 100644 --- a/devtools/client/responsive.html/test/unit/xpcshell.ini +++ b/devtools/client/responsive.html/test/unit/xpcshell.ini @@ -8,7 +8,6 @@ firefox-appdir = browser [test_add_viewport.js] [test_change_device.js] [test_change_display_pixel_ratio.js] -[test_change_location.js] [test_change_network_throttling.js] [test_change_pixel_ratio.js] [test_resize_viewport.js] diff --git a/devtools/client/responsive.html/types.js b/devtools/client/responsive.html/types.js index 99d89cae6a9e..3130550a58e8 100644 --- a/devtools/client/responsive.html/types.js +++ b/devtools/client/responsive.html/types.js @@ -24,11 +24,6 @@ exports.loadableState = createEnum([ /* GLOBAL */ -/** - * The location of the document displayed in the viewport(s). - */ -exports.location = PropTypes.string; - /** * Whether to reload the page automatically when certain actions occur. */ @@ -130,16 +125,6 @@ exports.networkThrottling = { }; -/** - * Device pixel ratio for a given viewport. - */ -const pixelRatio = exports.pixelRatio = { - - // The device pixel ratio value - value: PropTypes.number, - -}; - /** * Touch simulation state for a given viewport. */ @@ -171,7 +156,7 @@ exports.viewport = { height: PropTypes.number, // The device pixel ratio of the viewport - pixelRatio: PropTypes.shape(pixelRatio), + pixelRatio: PropTypes.number, // The user context (container) ID for the viewport // Defaults to 0 meaning the default context From 21c79a18a8feef315c789cf55f893098496b7ba4 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Tue, 4 Sep 2018 18:34:18 +0300 Subject: [PATCH 38/80] Backed out changeset fd24042d3bfa (bug 1488420) for bc failures on browser_pdfjs_zoom.js. CLOSED TREE --- browser/extensions/pdfjs/README.mozilla | 4 +- .../pdfjs/content/PdfJsDefaultPreferences.jsm | 9 +- browser/extensions/pdfjs/content/build/pdf.js | 981 ++++---- .../pdfjs/content/build/pdf.worker.js | 2240 ++++++++--------- .../extensions/pdfjs/content/web/viewer.js | 91 +- browser/extensions/pdfjs/moz.yaml | 2 +- 6 files changed, 1636 insertions(+), 1691 deletions(-) diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index 0f0450636446..fb359a5f9a8f 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,5 +1,5 @@ This is the PDF.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 2.0.813 +Current extension version is: 2.0.775 -Taken from upstream commit: af89ec27 +Taken from upstream commit: 20cd1b35 diff --git a/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm b/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm index 7fede18a30fb..337d4299b301 100644 --- a/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm +++ b/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm @@ -1,4 +1,4 @@ -/* Copyright 2018 Mozilla Foundation +/* Copyright 2017 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,8 @@ * limitations under the License. */ -/* eslint-disable */ - // -// THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT MANUALLY! +// THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT MANUALLY! // "use strict"; @@ -27,7 +25,6 @@ var PdfJsDefaultPreferences = Object.freeze({ "sidebarViewOnLoad": 0, "cursorToolOnLoad": 0, "enableWebGL": false, - "eventBusDispatchToDOM": false, "pdfBugEnabled": false, "disableRange": false, "disableStream": false, @@ -42,5 +39,5 @@ var PdfJsDefaultPreferences = Object.freeze({ "disablePageMode": false, "disablePageLabels": false, "scrollModeOnLoad": 0, - "spreadModeOnLoad": 0 + "spreadModeOnLoad": 0, }); diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index f12d1562dde1..c6d6630bcfd2 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2018 Mozilla Foundation + * Copyright 2017 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -var pdfjsVersion = '2.0.813'; -var pdfjsBuild = 'af89ec27'; +var pdfjsVersion = '2.0.775'; +var pdfjsBuild = '20cd1b35'; var pdfjsSharedUtil = __w_pdfjs_require__(1); var pdfjsDisplayAPI = __w_pdfjs_require__(7); var pdfjsDisplayTextLayer = __w_pdfjs_require__(19); @@ -177,7 +177,7 @@ exports.apiCompatibilityParams = pdfjsDisplayAPICompatibility.apiCompatibilityPa Object.defineProperty(exports, "__esModule", { value: true }); -exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; +exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; __w_pdfjs_require__(2); @@ -191,16 +191,6 @@ const NativeImageDecoding = { DECODE: 'decode', DISPLAY: 'display' }; -const PermissionFlag = { - PRINT: 0x04, - MODIFY_CONTENTS: 0x08, - COPY: 0x10, - MODIFY_ANNOTATIONS: 0x20, - FILL_INTERACTIVE_FORMS: 0x100, - COPY_FOR_ACCESSIBILITY: 0x200, - ASSEMBLE: 0x400, - PRINT_HIGH_QUALITY: 0x800 -}; var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -923,7 +913,6 @@ exports.MissingPDFException = MissingPDFException; exports.NativeImageDecoding = NativeImageDecoding; exports.PasswordException = PasswordException; exports.PasswordResponses = PasswordResponses; -exports.PermissionFlag = PermissionFlag; exports.StreamType = StreamType; exports.TextRenderingMode = TextRenderingMode; exports.UnexpectedResponseException = UnexpectedResponseException; @@ -4226,7 +4215,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { } return worker.messageHandler.sendWithPromise('GetDocRequest', { docId, - apiVersion: '2.0.813', + apiVersion: '2.0.775', source: { data: source.data, url: source.url, @@ -4334,70 +4323,70 @@ var PDFDataRangeTransport = function pdfDataRangeTransportClosure() { }; return PDFDataRangeTransport; }(); -class PDFDocumentProxy { - constructor(pdfInfo, transport, loadingTask) { - this.loadingTask = loadingTask; +var PDFDocumentProxy = function PDFDocumentProxyClosure() { + function PDFDocumentProxy(pdfInfo, transport, loadingTask) { this._pdfInfo = pdfInfo; - this._transport = transport; + this.transport = transport; + this.loadingTask = loadingTask; } - get numPages() { - return this._pdfInfo.numPages; - } - get fingerprint() { - return this._pdfInfo.fingerprint; - } - getPage(pageNumber) { - return this._transport.getPage(pageNumber); - } - getPageIndex(ref) { - return this._transport.getPageIndex(ref); - } - getDestinations() { - return this._transport.getDestinations(); - } - getDestination(id) { - return this._transport.getDestination(id); - } - getPageLabels() { - return this._transport.getPageLabels(); - } - getPageMode() { - return this._transport.getPageMode(); - } - getAttachments() { - return this._transport.getAttachments(); - } - getJavaScript() { - return this._transport.getJavaScript(); - } - getOutline() { - return this._transport.getOutline(); - } - getPermissions() { - return this._transport.getPermissions(); - } - getMetadata() { - return this._transport.getMetadata(); - } - getData() { - return this._transport.getData(); - } - getDownloadInfo() { - return this._transport.downloadInfoCapability.promise; - } - getStats() { - return this._transport.getStats(); - } - cleanup() { - this._transport.startCleanup(); - } - destroy() { - return this.loadingTask.destroy(); - } - get loadingParams() { - return this._transport.loadingParams; - } -} + PDFDocumentProxy.prototype = { + get numPages() { + return this._pdfInfo.numPages; + }, + get fingerprint() { + return this._pdfInfo.fingerprint; + }, + getPage(pageNumber) { + return this.transport.getPage(pageNumber); + }, + getPageIndex: function PDFDocumentProxy_getPageIndex(ref) { + return this.transport.getPageIndex(ref); + }, + getDestinations: function PDFDocumentProxy_getDestinations() { + return this.transport.getDestinations(); + }, + getDestination: function PDFDocumentProxy_getDestination(id) { + return this.transport.getDestination(id); + }, + getPageLabels: function PDFDocumentProxy_getPageLabels() { + return this.transport.getPageLabels(); + }, + getPageMode() { + return this.transport.getPageMode(); + }, + getAttachments: function PDFDocumentProxy_getAttachments() { + return this.transport.getAttachments(); + }, + getJavaScript() { + return this.transport.getJavaScript(); + }, + getOutline: function PDFDocumentProxy_getOutline() { + return this.transport.getOutline(); + }, + getMetadata: function PDFDocumentProxy_getMetadata() { + return this.transport.getMetadata(); + }, + getData: function PDFDocumentProxy_getData() { + return this.transport.getData(); + }, + getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() { + return this.transport.downloadInfoCapability.promise; + }, + getStats: function PDFDocumentProxy_getStats() { + return this.transport.getStats(); + }, + cleanup: function PDFDocumentProxy_cleanup() { + this.transport.startCleanup(); + }, + destroy: function PDFDocumentProxy_destroy() { + return this.loadingTask.destroy(); + }, + get loadingParams() { + return this.transport.loadingParams; + } + }; + return PDFDocumentProxy; +}(); var PDFPageProxy = function PDFPageProxyClosure() { function PDFPageProxy(pageIndex, pageInfo, transport, pdfBug = false) { this.pageIndex = pageIndex; @@ -4911,8 +4900,8 @@ var PDFWorker = function PDFWorkerClosure() { }; return PDFWorker; }(); -class WorkerTransport { - constructor(messageHandler, loadingTask, networkStream, params) { +var WorkerTransport = function WorkerTransportClosure() { + function WorkerTransport(messageHandler, loadingTask, networkStream, params) { this.messageHandler = messageHandler; this.loadingTask = loadingTask; this.commonObjs = new PDFObjects(); @@ -4933,430 +4922,446 @@ class WorkerTransport { this.downloadInfoCapability = (0, _util.createPromiseCapability)(); this.setupMessageHandler(); } - destroy() { - if (this.destroyCapability) { + WorkerTransport.prototype = { + destroy: function WorkerTransport_destroy() { + if (this.destroyCapability) { + return this.destroyCapability.promise; + } + this.destroyed = true; + this.destroyCapability = (0, _util.createPromiseCapability)(); + if (this._passwordCapability) { + this._passwordCapability.reject(new Error('Worker was destroyed during onPassword callback')); + } + var waitOn = []; + this.pageCache.forEach(function (page) { + if (page) { + waitOn.push(page._destroy()); + } + }); + this.pageCache = []; + this.pagePromises = []; + var terminated = this.messageHandler.sendWithPromise('Terminate', null); + waitOn.push(terminated); + Promise.all(waitOn).then(() => { + this.fontLoader.clear(); + if (this._networkStream) { + this._networkStream.cancelAllRequests(); + } + if (this.messageHandler) { + this.messageHandler.destroy(); + this.messageHandler = null; + } + this.destroyCapability.resolve(); + }, this.destroyCapability.reject); return this.destroyCapability.promise; - } - this.destroyed = true; - this.destroyCapability = (0, _util.createPromiseCapability)(); - if (this._passwordCapability) { - this._passwordCapability.reject(new Error('Worker was destroyed during onPassword callback')); - } - const waitOn = []; - this.pageCache.forEach(function (page) { - if (page) { - waitOn.push(page._destroy()); - } - }); - this.pageCache = []; - this.pagePromises = []; - const terminated = this.messageHandler.sendWithPromise('Terminate', null); - waitOn.push(terminated); - Promise.all(waitOn).then(() => { - this.fontLoader.clear(); - if (this._networkStream) { - this._networkStream.cancelAllRequests(); - } - if (this.messageHandler) { - this.messageHandler.destroy(); - this.messageHandler = null; - } - this.destroyCapability.resolve(); - }, this.destroyCapability.reject); - return this.destroyCapability.promise; - } - setupMessageHandler() { - const { messageHandler, loadingTask } = this; - messageHandler.on('GetReader', function (data, sink) { - (0, _util.assert)(this._networkStream); - this._fullReader = this._networkStream.getFullReader(); - this._fullReader.onProgress = evt => { - this._lastProgress = { - loaded: evt.loaded, - total: evt.total - }; - }; - sink.onPull = () => { - this._fullReader.read().then(function ({ value, done }) { - if (done) { - sink.close(); - return; - } - (0, _util.assert)((0, _util.isArrayBuffer)(value)); - sink.enqueue(new Uint8Array(value), 1, [value]); - }).catch(reason => { - sink.error(reason); - }); - }; - sink.onCancel = reason => { - this._fullReader.cancel(reason); - }; - }, this); - messageHandler.on('ReaderHeadersReady', function (data) { - const headersCapability = (0, _util.createPromiseCapability)(); - const fullReader = this._fullReader; - fullReader.headersReady.then(() => { - if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { - if (this._lastProgress) { - if (loadingTask.onProgress) { - loadingTask.onProgress(this._lastProgress); - } - } - fullReader.onProgress = evt => { - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: evt.loaded, - total: evt.total - }); - } + }, + setupMessageHandler: function WorkerTransport_setupMessageHandler() { + var messageHandler = this.messageHandler; + var loadingTask = this.loadingTask; + messageHandler.on('GetReader', function (data, sink) { + (0, _util.assert)(this._networkStream); + this._fullReader = this._networkStream.getFullReader(); + this._fullReader.onProgress = evt => { + this._lastProgress = { + loaded: evt.loaded, + total: evt.total }; - } - headersCapability.resolve({ - isStreamingSupported: fullReader.isStreamingSupported, - isRangeSupported: fullReader.isRangeSupported, - contentLength: fullReader.contentLength - }); - }, headersCapability.reject); - return headersCapability.promise; - }, this); - messageHandler.on('GetRangeReader', function (data, sink) { - (0, _util.assert)(this._networkStream); - const rangeReader = this._networkStream.getRangeReader(data.begin, data.end); - sink.onPull = () => { - rangeReader.read().then(function ({ value, done }) { - if (done) { - sink.close(); - return; - } - (0, _util.assert)((0, _util.isArrayBuffer)(value)); - sink.enqueue(new Uint8Array(value), 1, [value]); - }).catch(reason => { - sink.error(reason); - }); - }; - sink.onCancel = reason => { - rangeReader.cancel(reason); - }; - }, this); - messageHandler.on('GetDoc', function ({ pdfInfo }) { - this.numPages = pdfInfo.numPages; - this.pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); - loadingTask._capability.resolve(this.pdfDocument); - }, this); - messageHandler.on('PasswordRequest', function (exception) { - this._passwordCapability = (0, _util.createPromiseCapability)(); - if (loadingTask.onPassword) { - const updatePassword = password => { - this._passwordCapability.resolve({ password }); }; - try { - loadingTask.onPassword(updatePassword, exception.code); - } catch (ex) { - this._passwordCapability.reject(ex); - } - } else { - this._passwordCapability.reject(new _util.PasswordException(exception.message, exception.code)); - } - return this._passwordCapability.promise; - }, this); - messageHandler.on('PasswordException', function (exception) { - loadingTask._capability.reject(new _util.PasswordException(exception.message, exception.code)); - }, this); - messageHandler.on('InvalidPDF', function (exception) { - loadingTask._capability.reject(new _util.InvalidPDFException(exception.message)); - }, this); - messageHandler.on('MissingPDF', function (exception) { - loadingTask._capability.reject(new _util.MissingPDFException(exception.message)); - }, this); - messageHandler.on('UnexpectedResponse', function (exception) { - loadingTask._capability.reject(new _util.UnexpectedResponseException(exception.message, exception.status)); - }, this); - messageHandler.on('UnknownError', function (exception) { - loadingTask._capability.reject(new _util.UnknownErrorException(exception.message, exception.details)); - }, this); - messageHandler.on('DataLoaded', function (data) { - this.downloadInfoCapability.resolve(data); - }, this); - messageHandler.on('StartRenderPage', function (data) { - if (this.destroyed) { - return; - } - const page = this.pageCache[data.pageIndex]; - page._stats.timeEnd('Page Request'); - page._startRenderPage(data.transparency, data.intent); - }, this); - messageHandler.on('RenderPageChunk', function (data) { - if (this.destroyed) { - return; - } - const page = this.pageCache[data.pageIndex]; - page._renderPageChunk(data.operatorList, data.intent); - }, this); - messageHandler.on('commonobj', function (data) { - if (this.destroyed) { - return; - } - const [id, type, exportedData] = data; - if (this.commonObjs.hasData(id)) { - return; - } - switch (type) { - case 'Font': - const params = this._params; - if ('error' in exportedData) { - const exportedError = exportedData.error; - (0, _util.warn)(`Error during font loading: ${exportedError}`); - this.commonObjs.resolve(id, exportedError); - break; - } - let fontRegistry = null; - if (params.pdfBug && _global_scope2.default.FontInspector && _global_scope2.default.FontInspector.enabled) { - fontRegistry = { - registerFont(font, url) { - _global_scope2.default['FontInspector'].fontAdded(font, url); + sink.onPull = () => { + this._fullReader.read().then(function ({ value, done }) { + if (done) { + sink.close(); + return; + } + (0, _util.assert)((0, _util.isArrayBuffer)(value)); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(reason => { + sink.error(reason); + }); + }; + sink.onCancel = reason => { + this._fullReader.cancel(reason); + }; + }, this); + messageHandler.on('ReaderHeadersReady', function (data) { + let headersCapability = (0, _util.createPromiseCapability)(); + let fullReader = this._fullReader; + fullReader.headersReady.then(() => { + if (!fullReader.isStreamingSupported || !fullReader.isRangeSupported) { + if (this._lastProgress) { + let loadingTask = this.loadingTask; + if (loadingTask.onProgress) { + loadingTask.onProgress(this._lastProgress); + } + } + fullReader.onProgress = evt => { + let loadingTask = this.loadingTask; + if (loadingTask.onProgress) { + loadingTask.onProgress({ + loaded: evt.loaded, + total: evt.total + }); } }; } - const font = new _font_loader.FontFaceObject(exportedData, { - isEvalSupported: params.isEvalSupported, - disableFontFace: params.disableFontFace, - ignoreErrors: params.ignoreErrors, - onUnsupportedFeature: this._onUnsupportedFeature.bind(this), - fontRegistry + headersCapability.resolve({ + isStreamingSupported: fullReader.isStreamingSupported, + isRangeSupported: fullReader.isRangeSupported, + contentLength: fullReader.contentLength }); - const fontReady = fontObjs => { - this.commonObjs.resolve(id, font); + }, headersCapability.reject); + return headersCapability.promise; + }, this); + messageHandler.on('GetRangeReader', function (data, sink) { + (0, _util.assert)(this._networkStream); + let _rangeReader = this._networkStream.getRangeReader(data.begin, data.end); + sink.onPull = () => { + _rangeReader.read().then(function ({ value, done }) { + if (done) { + sink.close(); + return; + } + (0, _util.assert)((0, _util.isArrayBuffer)(value)); + sink.enqueue(new Uint8Array(value), 1, [value]); + }).catch(reason => { + sink.error(reason); + }); + }; + sink.onCancel = reason => { + _rangeReader.cancel(reason); + }; + }, this); + messageHandler.on('GetDoc', function transportDoc({ pdfInfo }) { + this.numPages = pdfInfo.numPages; + var loadingTask = this.loadingTask; + var pdfDocument = new PDFDocumentProxy(pdfInfo, this, loadingTask); + this.pdfDocument = pdfDocument; + loadingTask._capability.resolve(pdfDocument); + }, this); + messageHandler.on('PasswordRequest', function transportPasswordRequest(exception) { + this._passwordCapability = (0, _util.createPromiseCapability)(); + if (loadingTask.onPassword) { + var updatePassword = password => { + this._passwordCapability.resolve({ password }); }; - this.fontLoader.bind([font], fontReady); - break; - case 'FontPath': - this.commonObjs.resolve(id, exportedData); - break; - default: - throw new Error(`Got unknown common object type ${type}`); - } - }, this); - messageHandler.on('obj', function (data) { - if (this.destroyed) { - return; - } - const [id, pageIndex, type, imageData] = data; - const pageProxy = this.pageCache[pageIndex]; - if (pageProxy.objs.hasData(id)) { - return; - } - switch (type) { - case 'JpegStream': - return new Promise((resolve, reject) => { - const img = new Image(); - img.onload = function () { - resolve(img); - }; - img.onerror = function () { - reject(new Error('Error during JPEG image loading')); - }; - img.src = imageData; - }).then(img => { - pageProxy.objs.resolve(id, img); - }); - case 'Image': - pageProxy.objs.resolve(id, imageData); - const MAX_IMAGE_SIZE_TO_STORE = 8000000; - if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { - pageProxy.cleanupAfterRender = true; + try { + loadingTask.onPassword(updatePassword, exception.code); + } catch (ex) { + this._passwordCapability.reject(ex); } - break; - default: - throw new Error(`Got unknown object type ${type}`); - } - }, this); - messageHandler.on('DocProgress', function (data) { - if (this.destroyed) { - return; - } - if (loadingTask.onProgress) { - loadingTask.onProgress({ - loaded: data.loaded, - total: data.total + } else { + this._passwordCapability.reject(new _util.PasswordException(exception.message, exception.code)); + } + return this._passwordCapability.promise; + }, this); + messageHandler.on('PasswordException', function transportPasswordException(exception) { + loadingTask._capability.reject(new _util.PasswordException(exception.message, exception.code)); + }, this); + messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) { + this.loadingTask._capability.reject(new _util.InvalidPDFException(exception.message)); + }, this); + messageHandler.on('MissingPDF', function transportMissingPDF(exception) { + this.loadingTask._capability.reject(new _util.MissingPDFException(exception.message)); + }, this); + messageHandler.on('UnexpectedResponse', function transportUnexpectedResponse(exception) { + this.loadingTask._capability.reject(new _util.UnexpectedResponseException(exception.message, exception.status)); + }, this); + messageHandler.on('UnknownError', function transportUnknownError(exception) { + this.loadingTask._capability.reject(new _util.UnknownErrorException(exception.message, exception.details)); + }, this); + messageHandler.on('DataLoaded', function transportPage(data) { + this.downloadInfoCapability.resolve(data); + }, this); + messageHandler.on('StartRenderPage', function transportRender(data) { + if (this.destroyed) { + return; + } + var page = this.pageCache[data.pageIndex]; + page._stats.timeEnd('Page Request'); + page._startRenderPage(data.transparency, data.intent); + }, this); + messageHandler.on('RenderPageChunk', function transportRender(data) { + if (this.destroyed) { + return; + } + var page = this.pageCache[data.pageIndex]; + page._renderPageChunk(data.operatorList, data.intent); + }, this); + messageHandler.on('commonobj', function transportObj(data) { + if (this.destroyed) { + return; + } + var id = data[0]; + var type = data[1]; + if (this.commonObjs.hasData(id)) { + return; + } + switch (type) { + case 'Font': + var exportedData = data[2]; + let params = this._params; + if ('error' in exportedData) { + var exportedError = exportedData.error; + (0, _util.warn)('Error during font loading: ' + exportedError); + this.commonObjs.resolve(id, exportedError); + break; + } + var fontRegistry = null; + if (params.pdfBug && _global_scope2.default.FontInspector && _global_scope2.default.FontInspector.enabled) { + fontRegistry = { + registerFont(font, url) { + _global_scope2.default['FontInspector'].fontAdded(font, url); + } + }; + } + var font = new _font_loader.FontFaceObject(exportedData, { + isEvalSupported: params.isEvalSupported, + disableFontFace: params.disableFontFace, + ignoreErrors: params.ignoreErrors, + onUnsupportedFeature: this._onUnsupportedFeature.bind(this), + fontRegistry + }); + var fontReady = fontObjs => { + this.commonObjs.resolve(id, font); + }; + this.fontLoader.bind([font], fontReady); + break; + case 'FontPath': + this.commonObjs.resolve(id, data[2]); + break; + default: + throw new Error(`Got unknown common object type ${type}`); + } + }, this); + messageHandler.on('obj', function transportObj(data) { + if (this.destroyed) { + return; + } + var id = data[0]; + var pageIndex = data[1]; + var type = data[2]; + var pageProxy = this.pageCache[pageIndex]; + var imageData; + if (pageProxy.objs.hasData(id)) { + return; + } + switch (type) { + case 'JpegStream': + imageData = data[3]; + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = function () { + resolve(img); + }; + img.onerror = function () { + reject(new Error('Error during JPEG image loading')); + }; + img.src = imageData; + }).then(img => { + pageProxy.objs.resolve(id, img); + }); + case 'Image': + imageData = data[3]; + pageProxy.objs.resolve(id, imageData); + var MAX_IMAGE_SIZE_TO_STORE = 8000000; + if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { + pageProxy.cleanupAfterRender = true; + } + break; + default: + throw new Error(`Got unknown object type ${type}`); + } + }, this); + messageHandler.on('DocProgress', function transportDocProgress(data) { + if (this.destroyed) { + return; + } + var loadingTask = this.loadingTask; + if (loadingTask.onProgress) { + loadingTask.onProgress({ + loaded: data.loaded, + total: data.total + }); + } + }, this); + messageHandler.on('PageError', function transportError(data) { + if (this.destroyed) { + return; + } + var page = this.pageCache[data.pageNum - 1]; + var intentState = page.intentStates[data.intent]; + if (intentState.displayReadyCapability) { + intentState.displayReadyCapability.reject(data.error); + } else { + throw new Error(data.error); + } + if (intentState.operatorList) { + intentState.operatorList.lastChunk = true; + for (var i = 0; i < intentState.renderTasks.length; i++) { + intentState.renderTasks[i].operatorListChanged(); + } + } + }, this); + messageHandler.on('UnsupportedFeature', this._onUnsupportedFeature, this); + messageHandler.on('JpegDecode', function (data) { + if (this.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + if (typeof document === 'undefined') { + return Promise.reject(new Error('"document" is not defined.')); + } + var imageUrl = data[0]; + var components = data[1]; + if (components !== 3 && components !== 1) { + return Promise.reject(new Error('Only 3 components or 1 component can be returned')); + } + return new Promise(function (resolve, reject) { + var img = new Image(); + img.onload = function () { + var width = img.width; + var height = img.height; + var size = width * height; + var rgbaLength = size * 4; + var buf = new Uint8ClampedArray(size * components); + var tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = width; + tmpCanvas.height = height; + var tmpCtx = tmpCanvas.getContext('2d'); + tmpCtx.drawImage(img, 0, 0); + var data = tmpCtx.getImageData(0, 0, width, height).data; + var i, j; + if (components === 3) { + for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { + buf[j] = data[i]; + buf[j + 1] = data[i + 1]; + buf[j + 2] = data[i + 2]; + } + } else if (components === 1) { + for (i = 0, j = 0; i < rgbaLength; i += 4, j++) { + buf[j] = data[i]; + } + } + resolve({ + data: buf, + width, + height + }); + }; + img.onerror = function () { + reject(new Error('JpegDecode failed to load image')); + }; + img.src = imageUrl; }); - } - }, this); - messageHandler.on('PageError', function (data) { + }, this); + messageHandler.on('FetchBuiltInCMap', function (data) { + if (this.destroyed) { + return Promise.reject(new Error('Worker was destroyed')); + } + return this.CMapReaderFactory.fetch({ name: data.name }); + }, this); + }, + _onUnsupportedFeature({ featureId }) { if (this.destroyed) { return; } - const page = this.pageCache[data.pageNum - 1]; - const intentState = page.intentStates[data.intent]; - if (intentState.displayReadyCapability) { - intentState.displayReadyCapability.reject(data.error); - } else { - throw new Error(data.error); + let loadingTask = this.loadingTask; + if (loadingTask.onUnsupportedFeature) { + loadingTask.onUnsupportedFeature(featureId); } - if (intentState.operatorList) { - intentState.operatorList.lastChunk = true; - for (let i = 0; i < intentState.renderTasks.length; i++) { - intentState.renderTasks[i].operatorListChanged(); + }, + getData: function WorkerTransport_getData() { + return this.messageHandler.sendWithPromise('GetData', null); + }, + getPage(pageNumber) { + if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) { + return Promise.reject(new Error('Invalid page request')); + } + var pageIndex = pageNumber - 1; + if (pageIndex in this.pagePromises) { + return this.pagePromises[pageIndex]; + } + var promise = this.messageHandler.sendWithPromise('GetPage', { pageIndex }).then(pageInfo => { + if (this.destroyed) { + throw new Error('Transport destroyed'); } - } - }, this); - messageHandler.on('UnsupportedFeature', this._onUnsupportedFeature, this); - messageHandler.on('JpegDecode', function (data) { - if (this.destroyed) { - return Promise.reject(new Error('Worker was destroyed')); - } - if (typeof document === 'undefined') { - return Promise.reject(new Error('"document" is not defined.')); - } - const [imageUrl, components] = data; - if (components !== 3 && components !== 1) { - return Promise.reject(new Error('Only 3 components or 1 component can be returned')); - } - return new Promise(function (resolve, reject) { - const img = new Image(); - img.onload = function () { - const width = img.width; - const height = img.height; - const size = width * height; - const rgbaLength = size * 4; - const buf = new Uint8ClampedArray(size * components); - const tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = width; - tmpCanvas.height = height; - const tmpCtx = tmpCanvas.getContext('2d'); - tmpCtx.drawImage(img, 0, 0); - const data = tmpCtx.getImageData(0, 0, width, height).data; - if (components === 3) { - for (let i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { - buf[j] = data[i]; - buf[j + 1] = data[i + 1]; - buf[j + 2] = data[i + 2]; - } - } else if (components === 1) { - for (let i = 0, j = 0; i < rgbaLength; i += 4, j++) { - buf[j] = data[i]; - } - } - resolve({ - data: buf, - width, - height - }); - }; - img.onerror = function () { - reject(new Error('JpegDecode failed to load image')); - }; - img.src = imageUrl; + let page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.pdfBug); + this.pageCache[pageIndex] = page; + return page; }); - }, this); - messageHandler.on('FetchBuiltInCMap', function (data) { - if (this.destroyed) { - return Promise.reject(new Error('Worker was destroyed')); + this.pagePromises[pageIndex] = promise; + return promise; + }, + getPageIndex: function WorkerTransport_getPageIndexByRef(ref) { + return this.messageHandler.sendWithPromise('GetPageIndex', { ref }).catch(function (reason) { + return Promise.reject(new Error(reason)); + }); + }, + getAnnotations: function WorkerTransport_getAnnotations(pageIndex, intent) { + return this.messageHandler.sendWithPromise('GetAnnotations', { + pageIndex, + intent + }); + }, + getDestinations: function WorkerTransport_getDestinations() { + return this.messageHandler.sendWithPromise('GetDestinations', null); + }, + getDestination: function WorkerTransport_getDestination(id) { + if (typeof id !== 'string') { + return Promise.reject(new Error('Invalid destination request.')); } - return this.CMapReaderFactory.fetch({ name: data.name }); - }, this); - } - _onUnsupportedFeature({ featureId }) { - if (this.destroyed) { - return; - } - if (this.loadingTask.onUnsupportedFeature) { - this.loadingTask.onUnsupportedFeature(featureId); - } - } - getData() { - return this.messageHandler.sendWithPromise('GetData', null); - } - getPage(pageNumber) { - if (!Number.isInteger(pageNumber) || pageNumber <= 0 || pageNumber > this.numPages) { - return Promise.reject(new Error('Invalid page request')); - } - const pageIndex = pageNumber - 1; - if (pageIndex in this.pagePromises) { - return this.pagePromises[pageIndex]; - } - const promise = this.messageHandler.sendWithPromise('GetPage', { pageIndex }).then(pageInfo => { - if (this.destroyed) { - throw new Error('Transport destroyed'); - } - const page = new PDFPageProxy(pageIndex, pageInfo, this, this._params.pdfBug); - this.pageCache[pageIndex] = page; - return page; - }); - this.pagePromises[pageIndex] = promise; - return promise; - } - getPageIndex(ref) { - return this.messageHandler.sendWithPromise('GetPageIndex', { ref }).catch(function (reason) { - return Promise.reject(new Error(reason)); - }); - } - getAnnotations(pageIndex, intent) { - return this.messageHandler.sendWithPromise('GetAnnotations', { - pageIndex, - intent - }); - } - getDestinations() { - return this.messageHandler.sendWithPromise('GetDestinations', null); - } - getDestination(id) { - if (typeof id !== 'string') { - return Promise.reject(new Error('Invalid destination request.')); - } - return this.messageHandler.sendWithPromise('GetDestination', { id }); - } - getPageLabels() { - return this.messageHandler.sendWithPromise('GetPageLabels', null); - } - getPageMode() { - return this.messageHandler.sendWithPromise('GetPageMode', null); - } - getAttachments() { - return this.messageHandler.sendWithPromise('GetAttachments', null); - } - getJavaScript() { - return this.messageHandler.sendWithPromise('GetJavaScript', null); - } - getOutline() { - return this.messageHandler.sendWithPromise('GetOutline', null); - } - getPermissions() { - return this.messageHandler.sendWithPromise('GetPermissions', null); - } - getMetadata() { - return this.messageHandler.sendWithPromise('GetMetadata', null).then(results => { - return { - info: results[0], - metadata: results[1] ? new _metadata.Metadata(results[1]) : null, - contentDispositionFilename: this._fullReader ? this._fullReader.filename : null - }; - }); - } - getStats() { - return this.messageHandler.sendWithPromise('GetStats', null); - } - startCleanup() { - this.messageHandler.sendWithPromise('Cleanup', null).then(() => { - for (let i = 0, ii = this.pageCache.length; i < ii; i++) { - const page = this.pageCache[i]; - if (page) { - page.cleanup(); + return this.messageHandler.sendWithPromise('GetDestination', { id }); + }, + getPageLabels: function WorkerTransport_getPageLabels() { + return this.messageHandler.sendWithPromise('GetPageLabels', null); + }, + getPageMode() { + return this.messageHandler.sendWithPromise('GetPageMode', null); + }, + getAttachments: function WorkerTransport_getAttachments() { + return this.messageHandler.sendWithPromise('GetAttachments', null); + }, + getJavaScript: function WorkerTransport_getJavaScript() { + return this.messageHandler.sendWithPromise('GetJavaScript', null); + }, + getOutline: function WorkerTransport_getOutline() { + return this.messageHandler.sendWithPromise('GetOutline', null); + }, + getMetadata: function WorkerTransport_getMetadata() { + return this.messageHandler.sendWithPromise('GetMetadata', null).then(results => { + return { + info: results[0], + metadata: results[1] ? new _metadata.Metadata(results[1]) : null, + contentDispositionFilename: this._fullReader ? this._fullReader.filename : null + }; + }); + }, + getStats: function WorkerTransport_getStats() { + return this.messageHandler.sendWithPromise('GetStats', null); + }, + startCleanup: function WorkerTransport_startCleanup() { + this.messageHandler.sendWithPromise('Cleanup', null).then(() => { + for (var i = 0, ii = this.pageCache.length; i < ii; i++) { + var page = this.pageCache[i]; + if (page) { + page.cleanup(); + } } - } - this.commonObjs.clear(); - this.fontLoader.clear(); - }); - } - get loadingParams() { - const params = this._params; - return (0, _util.shadow)(this, 'loadingParams', { - disableAutoFetch: params.disableAutoFetch, - disableCreateObjectURL: params.disableCreateObjectURL, - disableFontFace: params.disableFontFace, - nativeImageDecoderSupport: params.nativeImageDecoderSupport - }); - } -} + this.commonObjs.clear(); + this.fontLoader.clear(); + }); + }, + get loadingParams() { + let params = this._params; + return (0, _util.shadow)(this, 'loadingParams', { + disableAutoFetch: params.disableAutoFetch, + disableCreateObjectURL: params.disableCreateObjectURL, + disableFontFace: params.disableFontFace, + nativeImageDecoderSupport: params.nativeImageDecoderSupport + }); + } + }; + return WorkerTransport; +}(); var PDFObjects = function PDFObjectsClosure() { function PDFObjects() { this.objs = Object.create(null); @@ -5553,8 +5558,8 @@ var InternalRenderTask = function InternalRenderTaskClosure() { }(); var version, build; { - exports.version = version = '2.0.813'; - exports.build = build = 'af89ec27'; + exports.version = version = '2.0.775'; + exports.build = build = '20cd1b35'; } exports.getDocument = getDocument; exports.LoopbackPort = LoopbackPort; diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index 6267009d258f..b8981a25164b 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2018 Mozilla Foundation + * Copyright 2017 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -var pdfjsVersion = '2.0.813'; -var pdfjsBuild = 'af89ec27'; +var pdfjsVersion = '2.0.775'; +var pdfjsBuild = '20cd1b35'; var pdfjsCoreWorker = __w_pdfjs_require__(1); exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler; @@ -327,7 +327,7 @@ var WorkerMessageHandler = { var cancelXHRs = null; var WorkerTasks = []; let apiVersion = docParams.apiVersion; - let workerVersion = '2.0.813'; + let workerVersion = '2.0.775'; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); } @@ -569,9 +569,6 @@ var WorkerMessageHandler = { handler.on('GetOutline', function wphSetupGetOutline(data) { return pdfManager.ensureCatalog('documentOutline'); }); - handler.on('GetPermissions', function (data) { - return pdfManager.ensureCatalog('permissions'); - }); handler.on('GetMetadata', function wphSetupGetMetadata(data) { return Promise.all([pdfManager.ensureDoc('documentInfo'), pdfManager.ensureCatalog('metadata')]); }); @@ -718,7 +715,7 @@ exports.WorkerMessageHandler = WorkerMessageHandler; Object.defineProperty(exports, "__esModule", { value: true }); -exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PermissionFlag = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; +exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.URL = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.toRomanNumerals = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined; __w_pdfjs_require__(3); @@ -732,16 +729,6 @@ const NativeImageDecoding = { DECODE: 'decode', DISPLAY: 'display' }; -const PermissionFlag = { - PRINT: 0x04, - MODIFY_CONTENTS: 0x08, - COPY: 0x10, - MODIFY_ANNOTATIONS: 0x20, - FILL_INTERACTIVE_FORMS: 0x100, - COPY_FOR_ACCESSIBILITY: 0x200, - ASSEMBLE: 0x400, - PRINT_HIGH_QUALITY: 0x800 -}; var TextRenderingMode = { FILL: 0, STROKE: 1, @@ -1464,7 +1451,6 @@ exports.MissingPDFException = MissingPDFException; exports.NativeImageDecoding = NativeImageDecoding; exports.PasswordException = PasswordException; exports.PasswordResponses = PasswordResponses; -exports.PermissionFlag = PermissionFlag; exports.StreamType = StreamType; exports.TextRenderingMode = TextRenderingMode; exports.UnexpectedResponseException = UnexpectedResponseException; @@ -5759,540 +5745,519 @@ var _colorspace = __w_pdfjs_require__(25); function fetchDestination(dest) { return (0, _primitives.isDict)(dest) ? dest.get('D') : dest; } -class Catalog { - constructor(pdfManager, xref) { +var Catalog = function CatalogClosure() { + function Catalog(pdfManager, xref) { this.pdfManager = pdfManager; this.xref = xref; this.catDict = xref.getCatalogObj(); if (!(0, _primitives.isDict)(this.catDict)) { - throw new _util.FormatError('Catalog object is not a dictionary.'); + throw new _util.FormatError('catalog object is not a dictionary'); } this.fontCache = new _primitives.RefSetCache(); this.builtInCMapCache = new Map(); this.pageKidsCountCache = new _primitives.RefSetCache(); } - get metadata() { - const streamRef = this.catDict.getRaw('Metadata'); - if (!(0, _primitives.isRef)(streamRef)) { - return (0, _util.shadow)(this, 'metadata', null); - } - const suppressEncryption = !(this.xref.encrypt && this.xref.encrypt.encryptMetadata); - const stream = this.xref.fetch(streamRef, suppressEncryption); - let metadata; - if (stream && (0, _primitives.isDict)(stream.dict)) { - const type = stream.dict.get('Type'); - const subtype = stream.dict.get('Subtype'); - if ((0, _primitives.isName)(type, 'Metadata') && (0, _primitives.isName)(subtype, 'XML')) { - try { - metadata = (0, _util.stringToUTF8String)((0, _util.bytesToString)(stream.getBytes())); - } catch (e) { - if (e instanceof _util.MissingDataException) { - throw e; + Catalog.prototype = { + get metadata() { + var streamRef = this.catDict.getRaw('Metadata'); + if (!(0, _primitives.isRef)(streamRef)) { + return (0, _util.shadow)(this, 'metadata', null); + } + var encryptMetadata = !this.xref.encrypt ? false : this.xref.encrypt.encryptMetadata; + var stream = this.xref.fetch(streamRef, !encryptMetadata); + var metadata; + if (stream && (0, _primitives.isDict)(stream.dict)) { + var type = stream.dict.get('Type'); + var subtype = stream.dict.get('Subtype'); + if ((0, _primitives.isName)(type, 'Metadata') && (0, _primitives.isName)(subtype, 'XML')) { + try { + metadata = (0, _util.stringToUTF8String)((0, _util.bytesToString)(stream.getBytes())); + } catch (e) { + if (e instanceof _util.MissingDataException) { + throw e; + } + (0, _util.info)('Skipping invalid metadata.'); } - (0, _util.info)('Skipping invalid metadata.'); } } - } - return (0, _util.shadow)(this, 'metadata', metadata); - } - get toplevelPagesDict() { - const pagesObj = this.catDict.get('Pages'); - if (!(0, _primitives.isDict)(pagesObj)) { - throw new _util.FormatError('Invalid top-level pages dictionary.'); - } - return (0, _util.shadow)(this, 'toplevelPagesDict', pagesObj); - } - get documentOutline() { - let obj = null; - try { - obj = this._readDocumentOutline(); - } catch (ex) { - if (ex instanceof _util.MissingDataException) { - throw ex; + return (0, _util.shadow)(this, 'metadata', metadata); + }, + get toplevelPagesDict() { + var pagesObj = this.catDict.get('Pages'); + if (!(0, _primitives.isDict)(pagesObj)) { + throw new _util.FormatError('invalid top-level pages dictionary'); } - (0, _util.warn)('Unable to read document outline.'); - } - return (0, _util.shadow)(this, 'documentOutline', obj); - } - _readDocumentOutline() { - let obj = this.catDict.get('Outlines'); - if (!(0, _primitives.isDict)(obj)) { - return null; - } - obj = obj.getRaw('First'); - if (!(0, _primitives.isRef)(obj)) { - return null; - } - const root = { items: [] }; - const queue = [{ - obj, - parent: root - }]; - const processed = new _primitives.RefSet(); - processed.put(obj); - const xref = this.xref, + return (0, _util.shadow)(this, 'toplevelPagesDict', pagesObj); + }, + get documentOutline() { + var obj = null; + try { + obj = this.readDocumentOutline(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read document outline'); + } + return (0, _util.shadow)(this, 'documentOutline', obj); + }, + readDocumentOutline: function Catalog_readDocumentOutline() { + var obj = this.catDict.get('Outlines'); + if (!(0, _primitives.isDict)(obj)) { + return null; + } + obj = obj.getRaw('First'); + if (!(0, _primitives.isRef)(obj)) { + return null; + } + var root = { items: [] }; + var queue = [{ + obj, + parent: root + }]; + var processed = new _primitives.RefSet(); + processed.put(obj); + var xref = this.xref, blackColor = new Uint8ClampedArray(3); - while (queue.length > 0) { - const i = queue.shift(); - const outlineDict = xref.fetchIfRef(i.obj); - if (outlineDict === null) { - continue; - } - if (!outlineDict.has('Title')) { - throw new _util.FormatError('Invalid outline item encountered.'); - } - const data = { - url: null, - dest: null - }; - Catalog.parseDestDictionary({ - destDict: outlineDict, - resultObj: data, - docBaseUrl: this.pdfManager.docBaseUrl - }); - const title = outlineDict.get('Title'); - const flags = outlineDict.get('F') || 0; - const color = outlineDict.getArray('C'); - let rgbColor = blackColor; - if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { - rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); - } - const outlineItem = { - dest: data.dest, - url: data.url, - unsafeUrl: data.unsafeUrl, - newWindow: data.newWindow, - title: (0, _util.stringToPDFString)(title), - color: rgbColor, - count: outlineDict.get('Count'), - bold: !!(flags & 2), - italic: !!(flags & 1), - items: [] - }; - i.parent.items.push(outlineItem); - obj = outlineDict.getRaw('First'); - if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { - queue.push({ - obj, - parent: outlineItem + while (queue.length > 0) { + var i = queue.shift(); + var outlineDict = xref.fetchIfRef(i.obj); + if (outlineDict === null) { + continue; + } + if (!outlineDict.has('Title')) { + throw new _util.FormatError('Invalid outline item'); + } + var data = { + url: null, + dest: null + }; + Catalog.parseDestDictionary({ + destDict: outlineDict, + resultObj: data, + docBaseUrl: this.pdfManager.docBaseUrl }); - processed.put(obj); + var title = outlineDict.get('Title'); + var flags = outlineDict.get('F') || 0; + var color = outlineDict.getArray('C'), + rgbColor = blackColor; + if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) { + rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0); + } + var outlineItem = { + dest: data.dest, + url: data.url, + unsafeUrl: data.unsafeUrl, + newWindow: data.newWindow, + title: (0, _util.stringToPDFString)(title), + color: rgbColor, + count: outlineDict.get('Count'), + bold: !!(flags & 2), + italic: !!(flags & 1), + items: [] + }; + i.parent.items.push(outlineItem); + obj = outlineDict.getRaw('First'); + if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { + queue.push({ + obj, + parent: outlineItem + }); + processed.put(obj); + } + obj = outlineDict.getRaw('Next'); + if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { + queue.push({ + obj, + parent: i.parent + }); + processed.put(obj); + } } - obj = outlineDict.getRaw('Next'); - if ((0, _primitives.isRef)(obj) && !processed.has(obj)) { - queue.push({ - obj, - parent: i.parent + return root.items.length > 0 ? root.items : null; + }, + get numPages() { + var obj = this.toplevelPagesDict.get('Count'); + if (!Number.isInteger(obj)) { + throw new _util.FormatError('page count in top level pages object is not an integer'); + } + return (0, _util.shadow)(this, 'numPages', obj); + }, + get destinations() { + const obj = this._readDests(), + dests = Object.create(null); + if (obj instanceof NameTree) { + const names = obj.getAll(); + for (let name in names) { + dests[name] = fetchDestination(names[name]); + } + } else if (obj instanceof _primitives.Dict) { + obj.forEach(function (key, value) { + if (value) { + dests[key] = fetchDestination(value); + } }); - processed.put(obj); } - } - return root.items.length > 0 ? root.items : null; - } - get permissions() { - let permissions = null; - try { - permissions = this._readPermissions(); - } catch (ex) { - if (ex instanceof _util.MissingDataException) { - throw ex; + return (0, _util.shadow)(this, 'destinations', dests); + }, + getDestination(destinationId) { + const obj = this._readDests(); + if (obj instanceof NameTree || obj instanceof _primitives.Dict) { + return fetchDestination(obj.get(destinationId) || null); } - (0, _util.warn)('Unable to read permissions.'); - } - return (0, _util.shadow)(this, 'permissions', permissions); - } - _readPermissions() { - const encrypt = this.xref.trailer.get('Encrypt'); - if (!(0, _primitives.isDict)(encrypt)) { return null; - } - let flags = encrypt.get('P'); - if (!(0, _util.isNum)(flags)) { - return null; - } - flags += 2 ** 32; - const permissions = []; - for (const key in _util.PermissionFlag) { - const value = _util.PermissionFlag[key]; - if (flags & value) { - permissions.push(value); + }, + _readDests() { + const obj = this.catDict.get('Names'); + if (obj && obj.has('Dests')) { + return new NameTree(obj.getRaw('Dests'), this.xref); + } else if (this.catDict.has('Dests')) { + return this.catDict.get('Dests'); } - } - return permissions; - } - get numPages() { - const obj = this.toplevelPagesDict.get('Count'); - if (!Number.isInteger(obj)) { - throw new _util.FormatError('Page count in top-level pages dictionary is not an integer.'); - } - return (0, _util.shadow)(this, 'numPages', obj); - } - get destinations() { - const obj = this._readDests(), - dests = Object.create(null); - if (obj instanceof NameTree) { - const names = obj.getAll(); - for (let name in names) { - dests[name] = fetchDestination(names[name]); + }, + get pageLabels() { + var obj = null; + try { + obj = this.readPageLabels(); + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + (0, _util.warn)('Unable to read page labels.'); } - } else if (obj instanceof _primitives.Dict) { - obj.forEach(function (key, value) { - if (value) { - dests[key] = fetchDestination(value); - } - }); - } - return (0, _util.shadow)(this, 'destinations', dests); - } - getDestination(destinationId) { - const obj = this._readDests(); - if (obj instanceof NameTree || obj instanceof _primitives.Dict) { - return fetchDestination(obj.get(destinationId) || null); - } - return null; - } - _readDests() { - const obj = this.catDict.get('Names'); - if (obj && obj.has('Dests')) { - return new NameTree(obj.getRaw('Dests'), this.xref); - } else if (this.catDict.has('Dests')) { - return this.catDict.get('Dests'); - } - } - get pageLabels() { - let obj = null; - try { - obj = this._readPageLabels(); - } catch (ex) { - if (ex instanceof _util.MissingDataException) { - throw ex; + return (0, _util.shadow)(this, 'pageLabels', obj); + }, + readPageLabels: function Catalog_readPageLabels() { + var obj = this.catDict.getRaw('PageLabels'); + if (!obj) { + return null; } - (0, _util.warn)('Unable to read page labels.'); - } - return (0, _util.shadow)(this, 'pageLabels', obj); - } - _readPageLabels() { - const obj = this.catDict.getRaw('PageLabels'); - if (!obj) { - return null; - } - const pageLabels = new Array(this.numPages); - let style = null, - prefix = ''; - const numberTree = new NumberTree(obj, this.xref); - const nums = numberTree.getAll(); - let currentLabel = '', - currentIndex = 1; - for (let i = 0, ii = this.numPages; i < ii; i++) { - if (i in nums) { - const labelDict = nums[i]; - if (!(0, _primitives.isDict)(labelDict)) { - throw new _util.FormatError('PageLabel is not a dictionary.'); - } - if (labelDict.has('Type') && !(0, _primitives.isName)(labelDict.get('Type'), 'PageLabel')) { - throw new _util.FormatError('Invalid type in PageLabel dictionary.'); - } - if (labelDict.has('S')) { - const s = labelDict.get('S'); - if (!(0, _primitives.isName)(s)) { - throw new _util.FormatError('Invalid style in PageLabel dictionary.'); - } - style = s.name; - } else { - style = null; - } - if (labelDict.has('P')) { - const p = labelDict.get('P'); - if (!(0, _util.isString)(p)) { - throw new _util.FormatError('Invalid prefix in PageLabel dictionary.'); - } - prefix = (0, _util.stringToPDFString)(p); - } else { - prefix = ''; - } - if (labelDict.has('St')) { - const st = labelDict.get('St'); - if (!(Number.isInteger(st) && st >= 1)) { - throw new _util.FormatError('Invalid start in PageLabel dictionary.'); - } - currentIndex = st; - } else { + var pageLabels = new Array(this.numPages); + var style = null; + var prefix = ''; + var numberTree = new NumberTree(obj, this.xref); + var nums = numberTree.getAll(); + var currentLabel = '', currentIndex = 1; - } - } - switch (style) { - case 'D': - currentLabel = currentIndex; - break; - case 'R': - case 'r': - currentLabel = (0, _util.toRomanNumerals)(currentIndex, style === 'r'); - break; - case 'A': - case 'a': - const LIMIT = 26; - const A_UPPER_CASE = 0x41, - A_LOWER_CASE = 0x61; - const baseCharCode = style === 'a' ? A_LOWER_CASE : A_UPPER_CASE; - const letterIndex = currentIndex - 1; - const character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); - const charBuf = []; - for (let j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) { - charBuf.push(character); + for (var i = 0, ii = this.numPages; i < ii; i++) { + if (i in nums) { + const labelDict = nums[i]; + if (!(0, _primitives.isDict)(labelDict)) { + throw new _util.FormatError('The PageLabel is not a dictionary.'); } - currentLabel = charBuf.join(''); - break; - default: - if (style) { - throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`); + if (labelDict.has('Type') && !(0, _primitives.isName)(labelDict.get('Type'), 'PageLabel')) { + throw new _util.FormatError('Invalid type in PageLabel dictionary.'); } - currentLabel = ''; - } - pageLabels[i] = prefix + currentLabel; - currentIndex++; - } - return pageLabels; - } - get pageMode() { - const obj = this.catDict.get('PageMode'); - let pageMode = 'UseNone'; - if ((0, _primitives.isName)(obj)) { - switch (obj.name) { - case 'UseNone': - case 'UseOutlines': - case 'UseThumbs': - case 'FullScreen': - case 'UseOC': - case 'UseAttachments': - pageMode = obj.name; - } - } - return (0, _util.shadow)(this, 'pageMode', pageMode); - } - get attachments() { - const obj = this.catDict.get('Names'); - let attachments = null; - if (obj && obj.has('EmbeddedFiles')) { - const nameTree = new NameTree(obj.getRaw('EmbeddedFiles'), this.xref); - const names = nameTree.getAll(); - for (const name in names) { - const fs = new FileSpec(names[name], this.xref); - if (!attachments) { - attachments = Object.create(null); - } - attachments[(0, _util.stringToPDFString)(name)] = fs.serializable; - } - } - return (0, _util.shadow)(this, 'attachments', attachments); - } - get javaScript() { - const obj = this.catDict.get('Names'); - let javaScript = null; - function appendIfJavaScriptDict(jsDict) { - const type = jsDict.get('S'); - if (!(0, _primitives.isName)(type, 'JavaScript')) { - return; - } - let js = jsDict.get('JS'); - if ((0, _primitives.isStream)(js)) { - js = (0, _util.bytesToString)(js.getBytes()); - } else if (!(0, _util.isString)(js)) { - return; - } - if (!javaScript) { - javaScript = []; - } - javaScript.push((0, _util.stringToPDFString)(js)); - } - if (obj && obj.has('JavaScript')) { - const nameTree = new NameTree(obj.getRaw('JavaScript'), this.xref); - const names = nameTree.getAll(); - for (const name in names) { - const jsDict = names[name]; - if ((0, _primitives.isDict)(jsDict)) { - appendIfJavaScriptDict(jsDict); - } - } - } - const openActionDict = this.catDict.get('OpenAction'); - if ((0, _primitives.isDict)(openActionDict, 'Action')) { - const actionType = openActionDict.get('S'); - if ((0, _primitives.isName)(actionType, 'Named')) { - const action = openActionDict.get('N'); - if ((0, _primitives.isName)(action, 'Print')) { - if (!javaScript) { - javaScript = []; - } - javaScript.push('print({});'); - } - } else { - appendIfJavaScriptDict(openActionDict); - } - } - return (0, _util.shadow)(this, 'javaScript', javaScript); - } - cleanup() { - this.pageKidsCountCache.clear(); - const promises = []; - this.fontCache.forEach(function (promise) { - promises.push(promise); - }); - return Promise.all(promises).then(translatedFonts => { - for (let i = 0, ii = translatedFonts.length; i < ii; i++) { - const font = translatedFonts[i].dict; - delete font.translated; - } - this.fontCache.clear(); - this.builtInCMapCache.clear(); - }); - } - getPageDict(pageIndex) { - const capability = (0, _util.createPromiseCapability)(); - const nodesToVisit = [this.catDict.getRaw('Pages')]; - const xref = this.xref, - pageKidsCountCache = this.pageKidsCountCache; - let count, - currentPageIndex = 0; - function next() { - while (nodesToVisit.length) { - const currentNode = nodesToVisit.pop(); - if ((0, _primitives.isRef)(currentNode)) { - count = pageKidsCountCache.get(currentNode); - if (count > 0 && currentPageIndex + count < pageIndex) { - currentPageIndex += count; - continue; - } - xref.fetchAsync(currentNode).then(function (obj) { - if ((0, _primitives.isDict)(obj, 'Page') || (0, _primitives.isDict)(obj) && !obj.has('Kids')) { - if (pageIndex === currentPageIndex) { - if (currentNode && !pageKidsCountCache.has(currentNode)) { - pageKidsCountCache.put(currentNode, 1); - } - capability.resolve([obj, currentNode]); - } else { - currentPageIndex++; - next(); - } - return; + if (labelDict.has('S')) { + const s = labelDict.get('S'); + if (!(0, _primitives.isName)(s)) { + throw new _util.FormatError('Invalid style in PageLabel dictionary.'); } - nodesToVisit.push(obj); - next(); - }, capability.reject); - return; - } - if (!(0, _primitives.isDict)(currentNode)) { - capability.reject(new _util.FormatError('Page dictionary kid reference points to wrong type of object.')); - return; - } - count = currentNode.get('Count'); - if (Number.isInteger(count) && count >= 0) { - const objId = currentNode.objId; - if (objId && !pageKidsCountCache.has(objId)) { - pageKidsCountCache.put(objId, count); + style = s.name; + } else { + style = null; } - if (currentPageIndex + count <= pageIndex) { - currentPageIndex += count; - continue; - } - } - const kids = currentNode.get('Kids'); - if (!Array.isArray(kids)) { - if ((0, _primitives.isName)(currentNode.get('Type'), 'Page') || !currentNode.has('Type') && currentNode.has('Contents')) { - if (currentPageIndex === pageIndex) { - capability.resolve([currentNode, null]); - return; + if (labelDict.has('P')) { + const p = labelDict.get('P'); + if (!(0, _util.isString)(p)) { + throw new _util.FormatError('Invalid prefix in PageLabel dictionary.'); } - currentPageIndex++; - continue; + prefix = (0, _util.stringToPDFString)(p); + } else { + prefix = ''; } - capability.reject(new _util.FormatError('Page dictionary kids object is not an array.')); - return; - } - for (let last = kids.length - 1; last >= 0; last--) { - nodesToVisit.push(kids[last]); - } - } - capability.reject(new Error(`Page index ${pageIndex} not found.`)); - } - next(); - return capability.promise; - } - getPageIndex(pageRef) { - const xref = this.xref; - function pagesBeforeRef(kidRef) { - let total = 0, - parentRef; - return xref.fetchAsync(kidRef).then(function (node) { - if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, 'Page') && !((0, _primitives.isDict)(node) && !node.has('Type') && node.has('Contents'))) { - throw new _util.FormatError('The reference does not point to a /Page dictionary.'); - } - if (!node) { - return null; - } - if (!(0, _primitives.isDict)(node)) { - throw new _util.FormatError('Node must be a dictionary.'); - } - parentRef = node.getRaw('Parent'); - return node.getAsync('Parent'); - }).then(function (parent) { - if (!parent) { - return null; - } - if (!(0, _primitives.isDict)(parent)) { - throw new _util.FormatError('Parent must be a dictionary.'); - } - return parent.getAsync('Kids'); - }).then(function (kids) { - if (!kids) { - return null; - } - const kidPromises = []; - let found = false; - for (let i = 0, ii = kids.length; i < ii; i++) { - const kid = kids[i]; - if (!(0, _primitives.isRef)(kid)) { - throw new _util.FormatError('Kid must be a reference.'); + if (labelDict.has('St')) { + const st = labelDict.get('St'); + if (!(Number.isInteger(st) && st >= 1)) { + throw new _util.FormatError('Invalid start in PageLabel dictionary.'); + } + currentIndex = st; + } else { + currentIndex = 1; } - if ((0, _primitives.isRefsEqual)(kid, kidRef)) { - found = true; + } + switch (style) { + case 'D': + currentLabel = currentIndex; break; + case 'R': + case 'r': + currentLabel = (0, _util.toRomanNumerals)(currentIndex, style === 'r'); + break; + case 'A': + case 'a': + var LIMIT = 26; + var A_UPPER_CASE = 0x41, + A_LOWER_CASE = 0x61; + var baseCharCode = style === 'a' ? A_LOWER_CASE : A_UPPER_CASE; + var letterIndex = currentIndex - 1; + var character = String.fromCharCode(baseCharCode + letterIndex % LIMIT); + var charBuf = []; + for (var j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) { + charBuf.push(character); + } + currentLabel = charBuf.join(''); + break; + default: + if (style) { + throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`); + } + currentLabel = ''; + } + pageLabels[i] = prefix + currentLabel; + currentIndex++; + } + return pageLabels; + }, + get pageMode() { + let obj = this.catDict.get('PageMode'); + let pageMode = 'UseNone'; + if ((0, _primitives.isName)(obj)) { + switch (obj.name) { + case 'UseNone': + case 'UseOutlines': + case 'UseThumbs': + case 'FullScreen': + case 'UseOC': + case 'UseAttachments': + pageMode = obj.name; + } + } + return (0, _util.shadow)(this, 'pageMode', pageMode); + }, + get attachments() { + var xref = this.xref; + var attachments = null, + nameTreeRef; + var obj = this.catDict.get('Names'); + if (obj) { + nameTreeRef = obj.getRaw('EmbeddedFiles'); + } + if (nameTreeRef) { + var nameTree = new NameTree(nameTreeRef, xref); + var names = nameTree.getAll(); + for (var name in names) { + var fs = new FileSpec(names[name], xref); + if (!attachments) { + attachments = Object.create(null); } - kidPromises.push(xref.fetchAsync(kid).then(function (kid) { - if (!(0, _primitives.isDict)(kid)) { - throw new _util.FormatError('Kid node must be a dictionary.'); - } - if (kid.has('Count')) { - total += kid.get('Count'); - } else { - total++; - } - })); + attachments[(0, _util.stringToPDFString)(name)] = fs.serializable; } - if (!found) { - throw new _util.FormatError('Kid reference not found in parent\'s kids.'); + } + return (0, _util.shadow)(this, 'attachments', attachments); + }, + get javaScript() { + var xref = this.xref; + var obj = this.catDict.get('Names'); + let javaScript = null; + function appendIfJavaScriptDict(jsDict) { + var type = jsDict.get('S'); + if (!(0, _primitives.isName)(type, 'JavaScript')) { + return; } - return Promise.all(kidPromises).then(function () { - return [total, parentRef]; + var js = jsDict.get('JS'); + if ((0, _primitives.isStream)(js)) { + js = (0, _util.bytesToString)(js.getBytes()); + } else if (!(0, _util.isString)(js)) { + return; + } + if (!javaScript) { + javaScript = []; + } + javaScript.push((0, _util.stringToPDFString)(js)); + } + if (obj && obj.has('JavaScript')) { + var nameTree = new NameTree(obj.getRaw('JavaScript'), xref); + var names = nameTree.getAll(); + for (var name in names) { + var jsDict = names[name]; + if ((0, _primitives.isDict)(jsDict)) { + appendIfJavaScriptDict(jsDict); + } + } + } + var openactionDict = this.catDict.get('OpenAction'); + if ((0, _primitives.isDict)(openactionDict, 'Action')) { + var actionType = openactionDict.get('S'); + if ((0, _primitives.isName)(actionType, 'Named')) { + var action = openactionDict.get('N'); + if ((0, _primitives.isName)(action, 'Print')) { + if (!javaScript) { + javaScript = []; + } + javaScript.push('print({});'); + } + } else { + appendIfJavaScriptDict(openactionDict); + } + } + return (0, _util.shadow)(this, 'javaScript', javaScript); + }, + cleanup: function Catalog_cleanup() { + this.pageKidsCountCache.clear(); + var promises = []; + this.fontCache.forEach(function (promise) { + promises.push(promise); + }); + return Promise.all(promises).then(translatedFonts => { + for (var i = 0, ii = translatedFonts.length; i < ii; i++) { + var font = translatedFonts[i].dict; + delete font.translated; + } + this.fontCache.clear(); + this.builtInCMapCache.clear(); + }); + }, + getPageDict: function Catalog_getPageDict(pageIndex) { + var capability = (0, _util.createPromiseCapability)(); + var nodesToVisit = [this.catDict.getRaw('Pages')]; + var count, + currentPageIndex = 0; + var xref = this.xref, + pageKidsCountCache = this.pageKidsCountCache; + function next() { + while (nodesToVisit.length) { + var currentNode = nodesToVisit.pop(); + if ((0, _primitives.isRef)(currentNode)) { + count = pageKidsCountCache.get(currentNode); + if (count > 0 && currentPageIndex + count < pageIndex) { + currentPageIndex += count; + continue; + } + xref.fetchAsync(currentNode).then(function (obj) { + if ((0, _primitives.isDict)(obj, 'Page') || (0, _primitives.isDict)(obj) && !obj.has('Kids')) { + if (pageIndex === currentPageIndex) { + if (currentNode && !pageKidsCountCache.has(currentNode)) { + pageKidsCountCache.put(currentNode, 1); + } + capability.resolve([obj, currentNode]); + } else { + currentPageIndex++; + next(); + } + return; + } + nodesToVisit.push(obj); + next(); + }, capability.reject); + return; + } + if (!(0, _primitives.isDict)(currentNode)) { + capability.reject(new _util.FormatError('page dictionary kid reference points to wrong type of object')); + return; + } + count = currentNode.get('Count'); + if (Number.isInteger(count) && count >= 0) { + var objId = currentNode.objId; + if (objId && !pageKidsCountCache.has(objId)) { + pageKidsCountCache.put(objId, count); + } + if (currentPageIndex + count <= pageIndex) { + currentPageIndex += count; + continue; + } + } + var kids = currentNode.get('Kids'); + if (!Array.isArray(kids)) { + if ((0, _primitives.isName)(currentNode.get('Type'), 'Page') || !currentNode.has('Type') && currentNode.has('Contents')) { + if (currentPageIndex === pageIndex) { + capability.resolve([currentNode, null]); + return; + } + currentPageIndex++; + continue; + } + capability.reject(new _util.FormatError('page dictionary kids object is not an array')); + return; + } + for (var last = kids.length - 1; last >= 0; last--) { + nodesToVisit.push(kids[last]); + } + } + capability.reject(new Error('Page index ' + pageIndex + ' not found.')); + } + next(); + return capability.promise; + }, + getPageIndex: function Catalog_getPageIndex(pageRef) { + var xref = this.xref; + function pagesBeforeRef(kidRef) { + var total = 0; + var parentRef; + return xref.fetchAsync(kidRef).then(function (node) { + if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, 'Page') && !((0, _primitives.isDict)(node) && !node.has('Type') && node.has('Contents'))) { + throw new _util.FormatError('The reference does not point to a /Page Dict.'); + } + if (!node) { + return null; + } + if (!(0, _primitives.isDict)(node)) { + throw new _util.FormatError('node must be a Dict.'); + } + parentRef = node.getRaw('Parent'); + return node.getAsync('Parent'); + }).then(function (parent) { + if (!parent) { + return null; + } + if (!(0, _primitives.isDict)(parent)) { + throw new _util.FormatError('parent must be a Dict.'); + } + return parent.getAsync('Kids'); + }).then(function (kids) { + if (!kids) { + return null; + } + var kidPromises = []; + var found = false; + for (var i = 0; i < kids.length; i++) { + var kid = kids[i]; + if (!(0, _primitives.isRef)(kid)) { + throw new _util.FormatError('kid must be a Ref.'); + } + if ((0, _primitives.isRefsEqual)(kid, kidRef)) { + found = true; + break; + } + kidPromises.push(xref.fetchAsync(kid).then(function (kid) { + if (!(0, _primitives.isDict)(kid)) { + throw new _util.FormatError('kid node must be a Dict.'); + } + if (kid.has('Count')) { + var count = kid.get('Count'); + total += count; + } else { + total++; + } + })); + } + if (!found) { + throw new _util.FormatError('kid ref not found in parents kids'); + } + return Promise.all(kidPromises).then(function () { + return [total, parentRef]; + }); }); - }); + } + var total = 0; + function next(ref) { + return pagesBeforeRef(ref).then(function (args) { + if (!args) { + return total; + } + var count = args[0]; + var parentRef = args[1]; + total += count; + return next(parentRef); + }); + } + return next(pageRef); } - let total = 0; - function next(ref) { - return pagesBeforeRef(ref).then(function (args) { - if (!args) { - return total; - } - const [count, parentRef] = args; - total += count; - return next(parentRef); - }); - } - return next(pageRef); - } - static parseDestDictionary(params) { + }; + Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) { function addDefaultProtocolToUrl(url) { if (url.indexOf('www.') === 0) { - return `http://${url}`; + return 'http://' + url; } return url; } @@ -6303,30 +6268,30 @@ class Catalog { return url; } } - const destDict = params.destDict; + var destDict = params.destDict; if (!(0, _primitives.isDict)(destDict)) { - (0, _util.warn)('parseDestDictionary: `destDict` must be a dictionary.'); + (0, _util.warn)('parseDestDictionary: "destDict" must be a dictionary.'); return; } - const resultObj = params.resultObj; + var resultObj = params.resultObj; if (typeof resultObj !== 'object') { - (0, _util.warn)('parseDestDictionary: `resultObj` must be an object.'); + (0, _util.warn)('parseDestDictionary: "resultObj" must be an object.'); return; } - const docBaseUrl = params.docBaseUrl || null; - let action = destDict.get('A'), + var docBaseUrl = params.docBaseUrl || null; + var action = destDict.get('A'), url, dest; if (!(0, _primitives.isDict)(action) && destDict.has('Dest')) { action = destDict.get('Dest'); } if ((0, _primitives.isDict)(action)) { - const actionType = action.get('S'); + let actionType = action.get('S'); if (!(0, _primitives.isName)(actionType)) { (0, _util.warn)('parseDestDictionary: Invalid type in Action dictionary.'); return; } - const actionName = actionType.name; + let actionName = actionType.name; switch (actionName) { case 'URI': url = action.get('URI'); @@ -6341,19 +6306,19 @@ class Catalog { break; case 'Launch': case 'GoToR': - const urlDict = action.get('F'); + var urlDict = action.get('F'); if ((0, _primitives.isDict)(urlDict)) { url = urlDict.get('F') || null; } else if ((0, _util.isString)(urlDict)) { url = urlDict; } - let remoteDest = action.get('D'); + var remoteDest = action.get('D'); if (remoteDest) { if ((0, _primitives.isName)(remoteDest)) { remoteDest = remoteDest.name; } if ((0, _util.isString)(url)) { - const baseUrl = url.split('#')[0]; + let baseUrl = url.split('#')[0]; if ((0, _util.isString)(remoteDest)) { url = baseUrl + '#' + remoteDest; } else if (Array.isArray(remoteDest)) { @@ -6361,29 +6326,29 @@ class Catalog { } } } - const newWindow = action.get('NewWindow'); + var newWindow = action.get('NewWindow'); if ((0, _util.isBool)(newWindow)) { resultObj.newWindow = newWindow; } break; case 'Named': - const namedAction = action.get('N'); + var namedAction = action.get('N'); if ((0, _primitives.isName)(namedAction)) { resultObj.action = namedAction.name; } break; case 'JavaScript': - const jsAction = action.get('JS'); - let js; + var jsAction = action.get('JS'), + js; if ((0, _primitives.isStream)(jsAction)) { js = (0, _util.bytesToString)(jsAction.getBytes()); } else if ((0, _util.isString)(jsAction)) { js = jsAction; } if (js) { - const URL_OPEN_METHODS = ['app.launchURL', 'window.open']; - const regex = new RegExp('^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') + ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i'); - const jsUrl = regex.exec((0, _util.stringToPDFString)(js)); + var URL_OPEN_METHODS = ['app.launchURL', 'window.open']; + var regex = new RegExp('^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') + ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i'); + var jsUrl = regex.exec((0, _util.stringToPDFString)(js)); if (jsUrl && jsUrl[2]) { url = jsUrl[2]; if (jsUrl[3] === 'true' && jsUrl[1] === 'app.launchURL') { @@ -6393,7 +6358,7 @@ class Catalog { } } default: - (0, _util.warn)(`parseDestDictionary: unsupported action type "${actionName}".`); + (0, _util.warn)(`parseDestDictionary: Unsupported Action type "${actionName}".`); break; } } else if (destDict.has('Dest')) { @@ -6401,7 +6366,7 @@ class Catalog { } if ((0, _util.isString)(url)) { url = tryConvertUrlEncoding(url); - const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl); + var absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl); if (absoluteUrl) { resultObj.url = absoluteUrl.href; } @@ -6415,8 +6380,9 @@ class Catalog { resultObj.dest = dest; } } - } -} + }; + return Catalog; +}(); var XRef = function XRefClosure() { function XRef(stream, pdfManager) { this.stream = stream; @@ -7923,77 +7889,66 @@ var Parser = function ParserClosure() { this.shift(); return imageStream; }, - _findStreamLength(startPos, signature) { - const { stream } = this.lexer; - stream.pos = startPos; - const SCAN_BLOCK_LENGTH = 2048; - const signatureLength = signature.length; - while (stream.pos < stream.end) { - const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH); - const scanLength = scanBytes.length - signatureLength; - if (scanLength <= 0) { - break; - } - let pos = 0; - while (pos < scanLength) { - let j = 0; - while (j < signatureLength && scanBytes[pos + j] === signature[j]) { - j++; - } - if (j >= signatureLength) { - stream.pos += pos; - return stream.pos - startPos; - } - pos++; - } - stream.pos += scanLength; - } - return -1; - }, makeStream: function Parser_makeStream(dict, cipherTransform) { var lexer = this.lexer; var stream = lexer.stream; lexer.skipToNextLine(); - const startPos = stream.pos - 1; + var pos = stream.pos - 1; var length = dict.get('Length'); if (!Number.isInteger(length)) { (0, _util.info)('Bad ' + length + ' attribute in stream'); length = 0; } - stream.pos = startPos + length; + stream.pos = pos + length; lexer.nextChar(); if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, 'endstream')) { this.shift(); } else { - const ENDSTREAM_SIGNATURE = new Uint8Array([0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D]); - let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE); - if (actualLength < 0) { - const MAX_TRUNCATION = 1; - for (let i = 1; i <= MAX_TRUNCATION; i++) { - const end = ENDSTREAM_SIGNATURE.length - i; - const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end); - let maybeLength = this._findStreamLength(startPos, TRUNCATED_SIGNATURE); - if (maybeLength >= 0) { - const lastByte = stream.peekBytes(end + 1)[end]; - if (!(0, _util.isSpace)(lastByte)) { - break; - } - (0, _util.info)(`Found "${(0, _util.bytesToString)(TRUNCATED_SIGNATURE)}" when ` + 'searching for endstream command.'); - actualLength = maybeLength; + stream.pos = pos; + var SCAN_BLOCK_SIZE = 2048; + var ENDSTREAM_SIGNATURE_LENGTH = 9; + var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D]; + var skipped = 0, + found = false, + i, + j; + while (stream.pos < stream.end) { + var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE); + var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH; + if (scanLength <= 0) { + break; + } + found = false; + i = 0; + while (i < scanLength) { + j = 0; + while (j < ENDSTREAM_SIGNATURE_LENGTH && scanBytes[i + j] === ENDSTREAM_SIGNATURE[j]) { + j++; + } + if (j >= ENDSTREAM_SIGNATURE_LENGTH) { + found = true; break; } + i++; } - if (actualLength < 0) { - throw new _util.FormatError('Missing endstream command.'); + if (found) { + skipped += i; + stream.pos += i; + break; } + skipped += scanLength; + stream.pos += scanLength; } - length = actualLength; + if (!found) { + throw new _util.FormatError('Missing endstream'); + } + length = skipped; lexer.nextChar(); this.shift(); this.shift(); } this.shift(); - stream = stream.makeSubStream(startPos, length, dict); + stream = stream.makeSubStream(pos, length, dict); if (cipherTransform) { stream = cipherTransform.createStream(stream, length); } @@ -12446,12 +12401,7 @@ let JpegStream = function JpegStreamClosure() { } const jpegImage = new _jpg.JpegImage(jpegOptions); jpegImage.parse(this.bytes); - let data = jpegImage.getData({ - width: this.drawWidth, - height: this.drawHeight, - forceRGB: this.forceRGB, - isSourcePDF: true - }); + let data = jpegImage.getData(this.drawWidth, this.drawHeight, this.forceRGB); this.buffer = data; this.bufferLength = data.length; this.eof = true; @@ -13287,7 +13237,7 @@ var JpegImage = function JpegImageClosure() { } this.numComponents = this.components.length; }, - _getLinearizedBlockData(width, height, isSourcePDF = false) { + _getLinearizedBlockData: function getLinearizedBlockData(width, height) { var scaleX = this.width / width, scaleY = this.height / height; var component, componentScaleX, componentScaleY, blocksPerScanline; @@ -13320,10 +13270,7 @@ var JpegImage = function JpegImageClosure() { } } } - let transform = this._decodeTransform; - if (!transform && numComponents === 4 && !isSourcePDF) { - transform = new Int32Array([-256, 255, -256, 255, -256, 255, -256, 255]); - } + const transform = this._decodeTransform; if (transform) { for (i = 0; i < dataLength;) { for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) { @@ -13333,7 +13280,7 @@ var JpegImage = function JpegImageClosure() { } return data; }, - get _isColorConversionNeeded() { + _isColorConversionNeeded() { if (this.adobe) { return !!this.adobe.transformCode; } @@ -13401,12 +13348,12 @@ var JpegImage = function JpegImageClosure() { } return data.subarray(0, offset); }, - getData({ width, height, forceRGB = false, isSourcePDF = false }) { + getData: function getData(width, height, forceRGBoutput) { if (this.numComponents > 4) { throw new JpegError('Unsupported color mode'); } - var data = this._getLinearizedBlockData(width, height, isSourcePDF); - if (this.numComponents === 1 && forceRGB) { + var data = this._getLinearizedBlockData(width, height); + if (this.numComponents === 1 && forceRGBoutput) { var dataLength = data.length; var rgbData = new Uint8ClampedArray(dataLength * 3); var offset = 0; @@ -13417,15 +13364,15 @@ var JpegImage = function JpegImageClosure() { rgbData[offset++] = grayColor; } return rgbData; - } else if (this.numComponents === 3 && this._isColorConversionNeeded) { + } else if (this.numComponents === 3 && this._isColorConversionNeeded()) { return this._convertYccToRgb(data); } else if (this.numComponents === 4) { - if (this._isColorConversionNeeded) { - if (forceRGB) { + if (this._isColorConversionNeeded()) { + if (forceRGBoutput) { return this._convertYcckToRgb(data); } return this._convertYcckToCmyk(data); - } else if (forceRGB) { + } else if (forceRGBoutput) { return this._convertCmykToRgb(data); } } @@ -16795,120 +16742,122 @@ var _util = __w_pdfjs_require__(2); var _primitives = __w_pdfjs_require__(12); -function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { - const COMPONENTS = 3; - alpha01 = alpha01 !== 1 ? 0 : alpha01; - let xRatio = w1 / w2; - let yRatio = h1 / h2; - let newIndex = 0, - oldIndex; - let xScaled = new Uint16Array(w2); - let w1Scanline = w1 * COMPONENTS; - for (let i = 0; i < w2; i++) { - xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; - } - for (let i = 0; i < h2; i++) { - const py = Math.floor(i * yRatio) * w1Scanline; - for (let j = 0; j < w2; j++) { - oldIndex = py + xScaled[j]; - dest[newIndex++] = src[oldIndex++]; - dest[newIndex++] = src[oldIndex++]; - dest[newIndex++] = src[oldIndex++]; - newIndex += alpha01; +var ColorSpace = function ColorSpaceClosure() { + function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) { + var COMPONENTS = 3; + alpha01 = alpha01 !== 1 ? 0 : alpha01; + var xRatio = w1 / w2; + var yRatio = h1 / h2; + var i, + j, + py, + newIndex = 0, + oldIndex; + var xScaled = new Uint16Array(w2); + var w1Scanline = w1 * COMPONENTS; + for (i = 0; i < w2; i++) { + xScaled[i] = Math.floor(i * xRatio) * COMPONENTS; } - } -} -class ColorSpace { - constructor(name, numComps) { - if (this.constructor === ColorSpace) { - (0, _util.unreachable)('Cannot initialize ColorSpace.'); - } - this.name = name; - this.numComps = numComps; - } - getRgb(src, srcOffset) { - let rgb = new Uint8ClampedArray(3); - this.getRgbItem(src, srcOffset, rgb, 0); - return rgb; - } - getRgbItem(src, srcOffset, dest, destOffset) { - (0, _util.unreachable)('Should not call ColorSpace.getRgbItem'); - } - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - (0, _util.unreachable)('Should not call ColorSpace.getRgbBuffer'); - } - getOutputLength(inputLength, alpha01) { - (0, _util.unreachable)('Should not call ColorSpace.getOutputLength'); - } - isPassthrough(bits) { - return false; - } - fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) { - let count = originalWidth * originalHeight; - let rgbBuf = null; - let numComponentColors = 1 << bpc; - let needsResizing = originalHeight !== height || originalWidth !== width; - if (this.isPassthrough(bpc)) { - rgbBuf = comps; - } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { - let allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors); - for (let i = 0; i < numComponentColors; i++) { - allColors[i] = i; + for (i = 0; i < h2; i++) { + py = Math.floor(i * yRatio) * w1Scanline; + for (j = 0; j < w2; j++) { + oldIndex = py + xScaled[j]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + dest[newIndex++] = src[oldIndex++]; + newIndex += alpha01; } - let colorMap = new Uint8ClampedArray(numComponentColors * 3); - this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0); - if (!needsResizing) { - let destPos = 0; - for (let i = 0; i < count; ++i) { - const key = comps[i] * 3; - dest[destPos++] = colorMap[key]; - dest[destPos++] = colorMap[key + 1]; - dest[destPos++] = colorMap[key + 2]; - destPos += alpha01; + } + } + function ColorSpace() { + (0, _util.unreachable)('should not call ColorSpace constructor'); + } + ColorSpace.prototype = { + getRgb(src, srcOffset) { + let rgb = new Uint8ClampedArray(3); + this.getRgbItem(src, srcOffset, rgb, 0); + return rgb; + }, + getRgbItem(src, srcOffset, dest, destOffset) { + (0, _util.unreachable)('Should not call ColorSpace.getRgbItem'); + }, + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + (0, _util.unreachable)('Should not call ColorSpace.getRgbBuffer'); + }, + getOutputLength(inputLength, alpha01) { + (0, _util.unreachable)('Should not call ColorSpace.getOutputLength'); + }, + isPassthrough(bits) { + return false; + }, + fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) { + var count = originalWidth * originalHeight; + var rgbBuf = null; + var numComponentColors = 1 << bpc; + var needsResizing = originalHeight !== height || originalWidth !== width; + var i, ii; + if (this.isPassthrough(bpc)) { + rgbBuf = comps; + } else if (this.numComps === 1 && count > numComponentColors && this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') { + var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors); + var key; + for (i = 0; i < numComponentColors; i++) { + allColors[i] = i; + } + var colorMap = new Uint8ClampedArray(numComponentColors * 3); + this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc, 0); + var destPos, rgbPos; + if (!needsResizing) { + destPos = 0; + for (i = 0; i < count; ++i) { + key = comps[i] * 3; + dest[destPos++] = colorMap[key]; + dest[destPos++] = colorMap[key + 1]; + dest[destPos++] = colorMap[key + 2]; + destPos += alpha01; + } + } else { + rgbBuf = new Uint8Array(count * 3); + rgbPos = 0; + for (i = 0; i < count; ++i) { + key = comps[i] * 3; + rgbBuf[rgbPos++] = colorMap[key]; + rgbBuf[rgbPos++] = colorMap[key + 1]; + rgbBuf[rgbPos++] = colorMap[key + 2]; + } } } else { - rgbBuf = new Uint8Array(count * 3); - let rgbPos = 0; - for (let i = 0; i < count; ++i) { - const key = comps[i] * 3; - rgbBuf[rgbPos++] = colorMap[key]; - rgbBuf[rgbPos++] = colorMap[key + 1]; - rgbBuf[rgbPos++] = colorMap[key + 2]; + if (!needsResizing) { + this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01); + } else { + rgbBuf = new Uint8ClampedArray(count * 3); + this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0); } } - } else { - if (!needsResizing) { - this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01); - } else { - rgbBuf = new Uint8ClampedArray(count * 3); - this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc, 0); - } - } - if (rgbBuf) { - if (needsResizing) { - resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, width, height, alpha01); - } else { - let destPos = 0, - rgbPos = 0; - for (let i = 0, ii = width * actualHeight; i < ii; i++) { - dest[destPos++] = rgbBuf[rgbPos++]; - dest[destPos++] = rgbBuf[rgbPos++]; - dest[destPos++] = rgbBuf[rgbPos++]; - destPos += alpha01; + if (rgbBuf) { + if (needsResizing) { + resizeRgbImage(rgbBuf, dest, originalWidth, originalHeight, width, height, alpha01); + } else { + rgbPos = 0; + destPos = 0; + for (i = 0, ii = width * actualHeight; i < ii; i++) { + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + dest[destPos++] = rgbBuf[rgbPos++]; + destPos += alpha01; + } } } - } - } - get usesZeroToOneRange() { - return (0, _util.shadow)(this, 'usesZeroToOneRange', true); - } - static parse(cs, xref, res, pdfFunctionFactory) { - let IR = this.parseToIR(cs, xref, res, pdfFunctionFactory); - return this.fromIR(IR); - } - static fromIR(IR) { - let name = Array.isArray(IR) ? IR[0] : IR; - let whitePoint, blackPoint, gamma; + }, + usesZeroToOneRange: true + }; + ColorSpace.parse = function (cs, xref, res, pdfFunctionFactory) { + let IR = ColorSpace.parseToIR(cs, xref, res, pdfFunctionFactory); + return ColorSpace.fromIR(IR); + }; + ColorSpace.fromIR = function (IR) { + var name = Array.isArray(IR) ? IR[0] : IR; + var whitePoint, blackPoint, gamma; switch (name) { case 'DeviceGrayCS': return this.singletons.gray; @@ -16925,34 +16874,34 @@ class ColorSpace { whitePoint = IR[1]; blackPoint = IR[2]; gamma = IR[3]; - let matrix = IR[4]; + var matrix = IR[4]; return new CalRGBCS(whitePoint, blackPoint, gamma, matrix); case 'PatternCS': - let basePatternCS = IR[1]; + var basePatternCS = IR[1]; if (basePatternCS) { - basePatternCS = this.fromIR(basePatternCS); + basePatternCS = ColorSpace.fromIR(basePatternCS); } return new PatternCS(basePatternCS); case 'IndexedCS': - let baseIndexedCS = IR[1]; - let hiVal = IR[2]; - let lookup = IR[3]; - return new IndexedCS(this.fromIR(baseIndexedCS), hiVal, lookup); + var baseIndexedCS = IR[1]; + var hiVal = IR[2]; + var lookup = IR[3]; + return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup); case 'AlternateCS': - let numComps = IR[1]; - let alt = IR[2]; - let tintFn = IR[3]; - return new AlternateCS(numComps, this.fromIR(alt), tintFn); + var numComps = IR[1]; + var alt = IR[2]; + var tintFn = IR[3]; + return new AlternateCS(numComps, ColorSpace.fromIR(alt), tintFn); case 'LabCS': whitePoint = IR[1]; blackPoint = IR[2]; - let range = IR[3]; + var range = IR[3]; return new LabCS(whitePoint, blackPoint, range); default: throw new _util.FormatError(`Unknown colorspace name: ${name}`); } - } - static parseToIR(cs, xref, res = null, pdfFunctionFactory) { + }; + ColorSpace.parseToIR = function (cs, xref, res = null, pdfFunctionFactory) { cs = xref.fetchIfRef(cs); if ((0, _primitives.isName)(cs)) { switch (cs.name) { @@ -16974,7 +16923,7 @@ class ColorSpace { let resCS = colorSpaces.get(cs.name); if (resCS) { if ((0, _primitives.isName)(resCS)) { - return this.parseToIR(resCS, xref, res, pdfFunctionFactory); + return ColorSpace.parseToIR(resCS, xref, res, pdfFunctionFactory); } cs = resCS; break; @@ -16985,8 +16934,8 @@ class ColorSpace { } } if (Array.isArray(cs)) { - let mode = xref.fetchIfRef(cs[0]).name; - let numComps, params, alt, whitePoint, blackPoint, gamma; + var mode = xref.fetchIfRef(cs[0]).name; + var numComps, params, alt, whitePoint, blackPoint, gamma; switch (mode) { case 'DeviceGray': case 'G': @@ -17008,16 +16957,16 @@ class ColorSpace { whitePoint = params.getArray('WhitePoint'); blackPoint = params.getArray('BlackPoint'); gamma = params.getArray('Gamma'); - let matrix = params.getArray('Matrix'); + var matrix = params.getArray('Matrix'); return ['CalRGBCS', whitePoint, blackPoint, gamma, matrix]; case 'ICCBased': - let stream = xref.fetchIfRef(cs[1]); - let dict = stream.dict; + var stream = xref.fetchIfRef(cs[1]); + var dict = stream.dict; numComps = dict.get('N'); alt = dict.get('Alternate'); if (alt) { - let altIR = this.parseToIR(alt, xref, res, pdfFunctionFactory); - let altCS = this.fromIR(altIR, pdfFunctionFactory); + var altIR = ColorSpace.parseToIR(alt, xref, res, pdfFunctionFactory); + var altCS = ColorSpace.fromIR(altIR, pdfFunctionFactory); if (altCS.numComps === numComps) { return altIR; } @@ -17032,40 +16981,40 @@ class ColorSpace { } break; case 'Pattern': - let basePatternCS = cs[1] || null; + var basePatternCS = cs[1] || null; if (basePatternCS) { - basePatternCS = this.parseToIR(basePatternCS, xref, res, pdfFunctionFactory); + basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res, pdfFunctionFactory); } return ['PatternCS', basePatternCS]; case 'Indexed': case 'I': - let baseIndexedCS = this.parseToIR(cs[1], xref, res, pdfFunctionFactory); - let hiVal = xref.fetchIfRef(cs[2]) + 1; - let lookup = xref.fetchIfRef(cs[3]); + var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res, pdfFunctionFactory); + var hiVal = xref.fetchIfRef(cs[2]) + 1; + var lookup = xref.fetchIfRef(cs[3]); if ((0, _primitives.isStream)(lookup)) { lookup = lookup.getBytes(); } return ['IndexedCS', baseIndexedCS, hiVal, lookup]; case 'Separation': case 'DeviceN': - let name = xref.fetchIfRef(cs[1]); + var name = xref.fetchIfRef(cs[1]); numComps = Array.isArray(name) ? name.length : 1; - alt = this.parseToIR(cs[2], xref, res, pdfFunctionFactory); + alt = ColorSpace.parseToIR(cs[2], xref, res, pdfFunctionFactory); let tintFn = pdfFunctionFactory.create(xref.fetchIfRef(cs[3])); return ['AlternateCS', numComps, alt, tintFn]; case 'Lab': params = xref.fetchIfRef(cs[1]); whitePoint = params.getArray('WhitePoint'); blackPoint = params.getArray('BlackPoint'); - let range = params.getArray('Range'); + var range = params.getArray('Range'); return ['LabCS', whitePoint, blackPoint, range]; default: throw new _util.FormatError(`unimplemented color space object "${mode}"`); } } throw new _util.FormatError(`unrecognized color space object: "${cs}"`); - } - static isDefaultDecode(decode, n) { + }; + ColorSpace.isDefaultDecode = function (decode, n) { if (!Array.isArray(decode)) { return true; } @@ -17073,97 +17022,112 @@ class ColorSpace { (0, _util.warn)('The decode map is not the correct length'); return true; } - for (let i = 0, ii = decode.length; i < ii; i += 2) { + for (var i = 0, ii = decode.length; i < ii; i += 2) { if (decode[i] !== 0 || decode[i + 1] !== 1) { return false; } } return true; - } - static get singletons() { - return (0, _util.shadow)(this, 'singletons', { - get gray() { - return (0, _util.shadow)(this, 'gray', new DeviceGrayCS()); - }, - get rgb() { - return (0, _util.shadow)(this, 'rgb', new DeviceRgbCS()); - }, - get cmyk() { - return (0, _util.shadow)(this, 'cmyk', new DeviceCmykCS()); - } - }); - } -} -class AlternateCS extends ColorSpace { - constructor(numComps, base, tintFn) { - super('Alternate', numComps); + }; + ColorSpace.singletons = { + get gray() { + return (0, _util.shadow)(this, 'gray', new DeviceGrayCS()); + }, + get rgb() { + return (0, _util.shadow)(this, 'rgb', new DeviceRgbCS()); + }, + get cmyk() { + return (0, _util.shadow)(this, 'cmyk', new DeviceCmykCS()); + } + }; + return ColorSpace; +}(); +var AlternateCS = function AlternateCSClosure() { + function AlternateCS(numComps, base, tintFn) { + this.name = 'Alternate'; + this.numComps = numComps; + this.defaultColor = new Float32Array(numComps); + for (var i = 0; i < numComps; ++i) { + this.defaultColor[i] = 1; + } this.base = base; this.tintFn = tintFn; this.tmpBuf = new Float32Array(base.numComps); } - getRgbItem(src, srcOffset, dest, destOffset) { - let tmpBuf = this.tmpBuf; - this.tintFn(src, srcOffset, tmpBuf, 0); - this.base.getRgbItem(tmpBuf, 0, dest, destOffset); - } - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let tintFn = this.tintFn; - let base = this.base; - let scale = 1 / ((1 << bits) - 1); - let baseNumComps = base.numComps; - let usesZeroToOneRange = base.usesZeroToOneRange; - let isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0; - let pos = isPassthrough ? destOffset : 0; - let baseBuf = isPassthrough ? dest : new Uint8ClampedArray(baseNumComps * count); - let numComps = this.numComps; - let scaled = new Float32Array(numComps); - let tinted = new Float32Array(baseNumComps); - let i, j; - for (i = 0; i < count; i++) { - for (j = 0; j < numComps; j++) { - scaled[j] = src[srcOffset++] * scale; - } - tintFn(scaled, 0, tinted, 0); - if (usesZeroToOneRange) { - for (j = 0; j < baseNumComps; j++) { - baseBuf[pos++] = tinted[j] * 255; + AlternateCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem(src, srcOffset, dest, destOffset) { + var tmpBuf = this.tmpBuf; + this.tintFn(src, srcOffset, tmpBuf, 0); + this.base.getRgbItem(tmpBuf, 0, dest, destOffset); + }, + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var tintFn = this.tintFn; + var base = this.base; + var scale = 1 / ((1 << bits) - 1); + var baseNumComps = base.numComps; + var usesZeroToOneRange = base.usesZeroToOneRange; + var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) && alpha01 === 0; + var pos = isPassthrough ? destOffset : 0; + let baseBuf = isPassthrough ? dest : new Uint8ClampedArray(baseNumComps * count); + var numComps = this.numComps; + var scaled = new Float32Array(numComps); + var tinted = new Float32Array(baseNumComps); + var i, j; + for (i = 0; i < count; i++) { + for (j = 0; j < numComps; j++) { + scaled[j] = src[srcOffset++] * scale; + } + tintFn(scaled, 0, tinted, 0); + if (usesZeroToOneRange) { + for (j = 0; j < baseNumComps; j++) { + baseBuf[pos++] = tinted[j] * 255; + } + } else { + base.getRgbItem(tinted, 0, baseBuf, pos); + pos += baseNumComps; } - } else { - base.getRgbItem(tinted, 0, baseBuf, pos); - pos += baseNumComps; } - } - if (!isPassthrough) { - base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); - } - } - getOutputLength(inputLength, alpha01) { - return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01); - } - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - } -} -class PatternCS extends ColorSpace { - constructor(baseCS) { - super('Pattern', null); + if (!isPassthrough) { + base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01); + } + }, + getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps / this.numComps, alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return AlternateCS; +}(); +var PatternCS = function PatternCSClosure() { + function PatternCS(baseCS) { + this.name = 'Pattern'; this.base = baseCS; } -} -class IndexedCS extends ColorSpace { - constructor(base, highVal, lookup) { - super('Indexed', 1); + PatternCS.prototype = {}; + return PatternCS; +}(); +var IndexedCS = function IndexedCSClosure() { + function IndexedCS(base, highVal, lookup) { + this.name = 'Indexed'; + this.numComps = 1; + this.defaultColor = new Uint8Array(this.numComps); this.base = base; this.highVal = highVal; - let baseNumComps = base.numComps; - let length = baseNumComps * highVal; + var baseNumComps = base.numComps; + var length = baseNumComps * highVal; if ((0, _primitives.isStream)(lookup)) { this.lookup = new Uint8Array(length); - let bytes = lookup.getBytes(length); + var bytes = lookup.getBytes(length); this.lookup.set(bytes); } else if ((0, _util.isString)(lookup)) { this.lookup = new Uint8Array(length); - for (let i = 0; i < length; ++i) { + for (var i = 0; i < length; ++i) { this.lookup[i] = lookup.charCodeAt(i); } } else if (lookup instanceof Uint8Array) { @@ -17172,193 +17136,272 @@ class IndexedCS extends ColorSpace { throw new _util.FormatError(`Unrecognized lookup table: ${lookup}`); } } - getRgbItem(src, srcOffset, dest, destOffset) { - let numComps = this.base.numComps; - let start = src[srcOffset] * numComps; - this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); + IndexedCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem(src, srcOffset, dest, destOffset) { + var numComps = this.base.numComps; + var start = src[srcOffset] * numComps; + this.base.getRgbBuffer(this.lookup, start, 1, dest, destOffset, 8, 0); + }, + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var base = this.base; + var numComps = base.numComps; + var outputDelta = base.getOutputLength(numComps, alpha01); + var lookup = this.lookup; + for (var i = 0; i < count; ++i) { + var lookupPos = src[srcOffset++] * numComps; + base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); + destOffset += outputDelta; + } + }, + getOutputLength(inputLength, alpha01) { + return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode(decodeMap) { + return true; + }, + usesZeroToOneRange: true + }; + return IndexedCS; +}(); +var DeviceGrayCS = function DeviceGrayCSClosure() { + function DeviceGrayCS() { + this.name = 'DeviceGray'; + this.numComps = 1; + this.defaultColor = new Float32Array(this.numComps); } - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let base = this.base; - let numComps = base.numComps; - let outputDelta = base.getOutputLength(numComps, alpha01); - let lookup = this.lookup; - for (let i = 0; i < count; ++i) { - let lookupPos = src[srcOffset++] * numComps; - base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01); - destOffset += outputDelta; - } + DeviceGrayCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem(src, srcOffset, dest, destOffset) { + let c = src[srcOffset] * 255; + dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; + }, + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + var scale = 255 / ((1 << bits) - 1); + var j = srcOffset, + q = destOffset; + for (var i = 0; i < count; ++i) { + let c = scale * src[j++]; + dest[q++] = c; + dest[q++] = c; + dest[q++] = c; + q += alpha01; + } + }, + getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01); + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return DeviceGrayCS; +}(); +var DeviceRgbCS = function DeviceRgbCSClosure() { + function DeviceRgbCS() { + this.name = 'DeviceRGB'; + this.numComps = 3; + this.defaultColor = new Float32Array(this.numComps); } - getOutputLength(inputLength, alpha01) { - return this.base.getOutputLength(inputLength * this.base.numComps, alpha01); - } - isDefaultDecode(decodeMap) { - return true; - } -} -class DeviceGrayCS extends ColorSpace { - constructor() { - super('DeviceGray', 1); - } - getRgbItem(src, srcOffset, dest, destOffset) { - let c = src[srcOffset] * 255; - dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c; - } - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let scale = 255 / ((1 << bits) - 1); - let j = srcOffset, - q = destOffset; - for (let i = 0; i < count; ++i) { - let c = scale * src[j++]; - dest[q++] = c; - dest[q++] = c; - dest[q++] = c; - q += alpha01; - } - } - getOutputLength(inputLength, alpha01) { - return inputLength * (3 + alpha01); - } - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - } -} -class DeviceRgbCS extends ColorSpace { - constructor() { - super('DeviceRGB', 3); - } - getRgbItem(src, srcOffset, dest, destOffset) { - dest[destOffset] = src[srcOffset] * 255; - dest[destOffset + 1] = src[srcOffset + 1] * 255; - dest[destOffset + 2] = src[srcOffset + 2] * 255; - } - getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - if (bits === 8 && alpha01 === 0) { - dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); - return; - } - let scale = 255 / ((1 << bits) - 1); - let j = srcOffset, - q = destOffset; - for (let i = 0; i < count; ++i) { - dest[q++] = scale * src[j++]; - dest[q++] = scale * src[j++]; - dest[q++] = scale * src[j++]; - q += alpha01; - } - } - getOutputLength(inputLength, alpha01) { - return inputLength * (3 + alpha01) / 3 | 0; - } - isPassthrough(bits) { - return bits === 8; - } - isDefaultDecode(decodeMap) { - return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - } -} -const DeviceCmykCS = function DeviceCmykCSClosure() { + DeviceRgbCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, + getRgbItem(src, srcOffset, dest, destOffset) { + dest[destOffset] = src[srcOffset] * 255; + dest[destOffset + 1] = src[srcOffset + 1] * 255; + dest[destOffset + 2] = src[srcOffset + 2] * 255; + }, + getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { + if (bits === 8 && alpha01 === 0) { + dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset); + return; + } + var scale = 255 / ((1 << bits) - 1); + var j = srcOffset, + q = destOffset; + for (var i = 0; i < count; ++i) { + dest[q++] = scale * src[j++]; + dest[q++] = scale * src[j++]; + dest[q++] = scale * src[j++]; + q += alpha01; + } + }, + getOutputLength(inputLength, alpha01) { + return inputLength * (3 + alpha01) / 3 | 0; + }, + isPassthrough(bits) { + return bits === 8; + }, + fillRgb: ColorSpace.prototype.fillRgb, + isDefaultDecode(decodeMap) { + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); + }, + usesZeroToOneRange: true + }; + return DeviceRgbCS; +}(); +var DeviceCmykCS = function DeviceCmykCSClosure() { function convertToRgb(src, srcOffset, srcScale, dest, destOffset) { - let c = src[srcOffset] * srcScale; - let m = src[srcOffset + 1] * srcScale; - let y = src[srcOffset + 2] * srcScale; - let k = src[srcOffset + 3] * srcScale; + var c = src[srcOffset] * srcScale; + var m = src[srcOffset + 1] * srcScale; + var y = src[srcOffset + 2] * srcScale; + var k = src[srcOffset + 3] * srcScale; dest[destOffset] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) + k * (-21.86122147463605 * k - 189.48180835922747); dest[destOffset + 1] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + k * (-20.737325471181034 * k - 187.80453709719578); dest[destOffset + 2] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505) + k * (-22.33816807309886 * k - 180.12613974708367); } - class DeviceCmykCS extends ColorSpace { - constructor() { - super('DeviceCMYK', 4); - } + function DeviceCmykCS() { + this.name = 'DeviceCMYK'; + this.numComps = 4; + this.defaultColor = new Float32Array(this.numComps); + this.defaultColor[3] = 1; + } + DeviceCmykCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(src, srcOffset, 1, dest, destOffset); - } + }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let scale = 1 / ((1 << bits) - 1); - for (let i = 0; i < count; i++) { + var scale = 1 / ((1 << bits) - 1); + for (var i = 0; i < count; i++) { convertToRgb(src, srcOffset, scale, dest, destOffset); srcOffset += 4; destOffset += 3 + alpha01; } - } + }, getOutputLength(inputLength, alpha01) { return inputLength / 4 * (3 + alpha01) | 0; - } + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - } - } + }, + usesZeroToOneRange: true + }; return DeviceCmykCS; }(); -const CalGrayCS = function CalGrayCSClosure() { +var CalGrayCS = function CalGrayCSClosure() { + function CalGrayCS(whitePoint, blackPoint, gamma) { + this.name = 'CalGray'; + this.numComps = 1; + this.defaultColor = new Float32Array(this.numComps); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space CalGray'); + } + blackPoint = blackPoint || [0, 0, 0]; + gamma = gamma || 1; + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + this.G = gamma; + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); + } + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + (0, _util.info)('Invalid BlackPoint for ' + this.name + ', falling back to default'); + this.XB = this.YB = this.ZB = 0; + } + if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { + (0, _util.warn)(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + ', ZB: ' + this.ZB + ', only default values are supported.'); + } + if (this.G < 1) { + (0, _util.info)('Invalid Gamma: ' + this.G + ' for ' + this.name + ', falling back to default'); + this.G = 1; + } + } function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { - let A = src[srcOffset] * scale; - let AG = Math.pow(A, cs.G); - let L = cs.YW * AG; + var A = src[srcOffset] * scale; + var AG = Math.pow(A, cs.G); + var L = cs.YW * AG; let val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0); dest[destOffset] = val; dest[destOffset + 1] = val; dest[destOffset + 2] = val; } - class CalGrayCS extends ColorSpace { - constructor(whitePoint, blackPoint, gamma) { - super('CalGray', 1); - if (!whitePoint) { - throw new _util.FormatError('WhitePoint missing - required for color space CalGray'); - } - blackPoint = blackPoint || [0, 0, 0]; - gamma = gamma || 1; - this.XW = whitePoint[0]; - this.YW = whitePoint[1]; - this.ZW = whitePoint[2]; - this.XB = blackPoint[0]; - this.YB = blackPoint[1]; - this.ZB = blackPoint[2]; - this.G = gamma; - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { - throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); - } - if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - (0, _util.info)(`Invalid BlackPoint for ${this.name}, falling back to default.`); - this.XB = this.YB = this.ZB = 0; - } - if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { - (0, _util.warn)(`${this.name}, BlackPoint: XB: ${this.XB}, YB: ${this.YB}, ` + `ZB: ${this.ZB}, only default values are supported.`); - } - if (this.G < 1) { - (0, _util.info)(`Invalid Gamma: ${this.G} for ${this.name}, ` + 'falling back to default.'); - this.G = 1; - } - } + CalGrayCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(this, src, srcOffset, dest, destOffset, 1); - } + }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let scale = 1 / ((1 << bits) - 1); - for (let i = 0; i < count; ++i) { + var scale = 1 / ((1 << bits) - 1); + for (var i = 0; i < count; ++i) { convertToRgb(this, src, srcOffset, dest, destOffset, scale); srcOffset += 1; destOffset += 3 + alpha01; } - } + }, getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01); - } + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - } - } + }, + usesZeroToOneRange: true + }; return CalGrayCS; }(); -const CalRGBCS = function CalRGBCSClosure() { - const BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]); - const BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]); - const SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252]); - const FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); - let tempNormalizeMatrix = new Float32Array(3); - let tempConvertMatrix1 = new Float32Array(3); - let tempConvertMatrix2 = new Float32Array(3); - const DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0; +var CalRGBCS = function CalRGBCSClosure() { + var BRADFORD_SCALE_MATRIX = new Float32Array([0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296]); + var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([0.9869929, -0.1470543, 0.1599627, 0.4323053, 0.5183603, 0.0492912, -0.0085287, 0.0400428, 0.9684867]); + var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([3.2404542, -1.5371385, -0.4985314, -0.9692660, 1.8760108, 0.0415560, 0.0556434, -0.2040259, 1.0572252]); + var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]); + var tempNormalizeMatrix = new Float32Array(3); + var tempConvertMatrix1 = new Float32Array(3); + var tempConvertMatrix2 = new Float32Array(3); + var DECODE_L_CONSTANT = Math.pow((8 + 16) / 116, 3) / 8.0; + function CalRGBCS(whitePoint, blackPoint, gamma, matrix) { + this.name = 'CalRGB'; + this.numComps = 3; + this.defaultColor = new Float32Array(this.numComps); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space CalRGB'); + } + blackPoint = blackPoint || new Float32Array(3); + gamma = gamma || new Float32Array([1, 1, 1]); + matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); + var XW = whitePoint[0]; + var YW = whitePoint[1]; + var ZW = whitePoint[2]; + this.whitePoint = whitePoint; + var XB = blackPoint[0]; + var YB = blackPoint[1]; + var ZB = blackPoint[2]; + this.blackPoint = blackPoint; + this.GR = gamma[0]; + this.GG = gamma[1]; + this.GB = gamma[2]; + this.MXA = matrix[0]; + this.MYA = matrix[1]; + this.MZA = matrix[2]; + this.MXB = matrix[3]; + this.MYB = matrix[4]; + this.MZB = matrix[5]; + this.MXC = matrix[6]; + this.MYC = matrix[7]; + this.MZC = matrix[8]; + if (XW < 0 || ZW < 0 || YW !== 1) { + throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); + } + if (XB < 0 || YB < 0 || ZB < 0) { + (0, _util.info)('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB + ', ' + ZB + '], falling back to default'); + this.blackPoint = new Float32Array(3); + } + if (this.GR < 0 || this.GG < 0 || this.GB < 0) { + (0, _util.info)('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB + '] for ' + this.name + ', falling back to default'); + this.GR = this.GG = this.GB = 1; + } + } function matrixProduct(a, b, result) { result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2]; @@ -17370,9 +17413,9 @@ const CalRGBCS = function CalRGBCSClosure() { result[2] = LMS[2] * 1 / sourceWhitePoint[2]; } function convertToD65(sourceWhitePoint, LMS, result) { - const D65X = 0.95047; - const D65Y = 1; - const D65Z = 1.08883; + var D65X = 0.95047; + var D65Y = 1; + var D65Z = 1.08883; result[0] = LMS[0] * D65X / sourceWhitePoint[0]; result[1] = LMS[1] * D65Y / sourceWhitePoint[1]; result[2] = LMS[2] * D65Z / sourceWhitePoint[2]; @@ -17402,19 +17445,19 @@ const CalRGBCS = function CalRGBCSClosure() { result[2] = XYZ_Flat[2]; return; } - let zeroDecodeL = decodeL(0); - let X_DST = zeroDecodeL; - let X_SRC = decodeL(sourceBlackPoint[0]); - let Y_DST = zeroDecodeL; - let Y_SRC = decodeL(sourceBlackPoint[1]); - let Z_DST = zeroDecodeL; - let Z_SRC = decodeL(sourceBlackPoint[2]); - let X_Scale = (1 - X_DST) / (1 - X_SRC); - let X_Offset = 1 - X_Scale; - let Y_Scale = (1 - Y_DST) / (1 - Y_SRC); - let Y_Offset = 1 - Y_Scale; - let Z_Scale = (1 - Z_DST) / (1 - Z_SRC); - let Z_Offset = 1 - Z_Scale; + var zeroDecodeL = decodeL(0); + var X_DST = zeroDecodeL; + var X_SRC = decodeL(sourceBlackPoint[0]); + var Y_DST = zeroDecodeL; + var Y_SRC = decodeL(sourceBlackPoint[1]); + var Z_DST = zeroDecodeL; + var Z_SRC = decodeL(sourceBlackPoint[2]); + var X_Scale = (1 - X_DST) / (1 - X_SRC); + var X_Offset = 1 - X_Scale; + var Y_Scale = (1 - Y_DST) / (1 - Y_SRC); + var Y_Offset = 1 - Y_Scale; + var Z_Scale = (1 - Z_DST) / (1 - Z_SRC); + var Z_Offset = 1 - Z_Scale; result[0] = XYZ_Flat[0] * X_Scale + X_Offset; result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset; result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset; @@ -17426,109 +17469,107 @@ const CalRGBCS = function CalRGBCSClosure() { result[2] = XYZ_In[2]; return; } - let LMS = result; + var LMS = result; matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); - let LMS_Flat = tempNormalizeMatrix; + var LMS_Flat = tempNormalizeMatrix; convertToFlat(sourceWhitePoint, LMS, LMS_Flat); matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result); } function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) { - let LMS = result; + var LMS = result; matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS); - let LMS_D65 = tempNormalizeMatrix; + var LMS_D65 = tempNormalizeMatrix; convertToD65(sourceWhitePoint, LMS, LMS_D65); matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result); } function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) { - let A = adjustToRange(0, 1, src[srcOffset] * scale); - let B = adjustToRange(0, 1, src[srcOffset + 1] * scale); - let C = adjustToRange(0, 1, src[srcOffset + 2] * scale); - let AGR = Math.pow(A, cs.GR); - let BGG = Math.pow(B, cs.GG); - let CGB = Math.pow(C, cs.GB); - let X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; - let Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; - let Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; - let XYZ = tempConvertMatrix1; + var A = adjustToRange(0, 1, src[srcOffset] * scale); + var B = adjustToRange(0, 1, src[srcOffset + 1] * scale); + var C = adjustToRange(0, 1, src[srcOffset + 2] * scale); + var AGR = Math.pow(A, cs.GR); + var BGG = Math.pow(B, cs.GG); + var CGB = Math.pow(C, cs.GB); + var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB; + var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB; + var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB; + var XYZ = tempConvertMatrix1; XYZ[0] = X; XYZ[1] = Y; XYZ[2] = Z; - let XYZ_Flat = tempConvertMatrix2; + var XYZ_Flat = tempConvertMatrix2; normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat); - let XYZ_Black = tempConvertMatrix1; + var XYZ_Black = tempConvertMatrix1; compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black); - let XYZ_D65 = tempConvertMatrix2; + var XYZ_D65 = tempConvertMatrix2; normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65); - let SRGB = tempConvertMatrix1; + var SRGB = tempConvertMatrix1; matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB); dest[destOffset] = sRGBTransferFunction(SRGB[0]) * 255; dest[destOffset + 1] = sRGBTransferFunction(SRGB[1]) * 255; dest[destOffset + 2] = sRGBTransferFunction(SRGB[2]) * 255; } - class CalRGBCS extends ColorSpace { - constructor(whitePoint, blackPoint, gamma, matrix) { - super('CalRGB', 3); - if (!whitePoint) { - throw new _util.FormatError('WhitePoint missing - required for color space CalRGB'); - } - blackPoint = blackPoint || new Float32Array(3); - gamma = gamma || new Float32Array([1, 1, 1]); - matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); - let XW = whitePoint[0]; - let YW = whitePoint[1]; - let ZW = whitePoint[2]; - this.whitePoint = whitePoint; - let XB = blackPoint[0]; - let YB = blackPoint[1]; - let ZB = blackPoint[2]; - this.blackPoint = blackPoint; - this.GR = gamma[0]; - this.GG = gamma[1]; - this.GB = gamma[2]; - this.MXA = matrix[0]; - this.MYA = matrix[1]; - this.MZA = matrix[2]; - this.MXB = matrix[3]; - this.MYB = matrix[4]; - this.MZB = matrix[5]; - this.MXC = matrix[6]; - this.MYC = matrix[7]; - this.MZC = matrix[8]; - if (XW < 0 || ZW < 0 || YW !== 1) { - throw new _util.FormatError(`Invalid WhitePoint components for ${this.name}` + ', no fallback available'); - } - if (XB < 0 || YB < 0 || ZB < 0) { - (0, _util.info)(`Invalid BlackPoint for ${this.name} [${XB}, ${YB}, ${ZB}], ` + 'falling back to default.'); - this.blackPoint = new Float32Array(3); - } - if (this.GR < 0 || this.GG < 0 || this.GB < 0) { - (0, _util.info)(`Invalid Gamma [${this.GR}, ${this.GG}, ${this.GB}] for ` + `${this.name}, falling back to default.`); - this.GR = this.GG = this.GB = 1; - } - } + CalRGBCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(this, src, srcOffset, dest, destOffset, 1); - } + }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let scale = 1 / ((1 << bits) - 1); - for (let i = 0; i < count; ++i) { + var scale = 1 / ((1 << bits) - 1); + for (var i = 0; i < count; ++i) { convertToRgb(this, src, srcOffset, dest, destOffset, scale); srcOffset += 3; destOffset += 3 + alpha01; } - } + }, getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01) / 3 | 0; - } + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, isDefaultDecode(decodeMap) { return ColorSpace.isDefaultDecode(decodeMap, this.numComps); - } - } + }, + usesZeroToOneRange: true + }; return CalRGBCS; }(); -const LabCS = function LabCSClosure() { +var LabCS = function LabCSClosure() { + function LabCS(whitePoint, blackPoint, range) { + this.name = 'Lab'; + this.numComps = 3; + this.defaultColor = new Float32Array(this.numComps); + if (!whitePoint) { + throw new _util.FormatError('WhitePoint missing - required for color space Lab'); + } + blackPoint = blackPoint || [0, 0, 0]; + range = range || [-100, 100, -100, 100]; + this.XW = whitePoint[0]; + this.YW = whitePoint[1]; + this.ZW = whitePoint[2]; + this.amin = range[0]; + this.amax = range[1]; + this.bmin = range[2]; + this.bmax = range[3]; + this.XB = blackPoint[0]; + this.YB = blackPoint[1]; + this.ZB = blackPoint[2]; + if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { + throw new _util.FormatError('Invalid WhitePoint components, no fallback available'); + } + if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { + (0, _util.info)('Invalid BlackPoint, falling back to default'); + this.XB = this.YB = this.ZB = 0; + } + if (this.amin > this.amax || this.bmin > this.bmax) { + (0, _util.info)('Invalid Range, falling back to defaults'); + this.amin = -100; + this.amax = 100; + this.bmin = -100; + this.bmax = 100; + } + } function fn_g(x) { - let result; + var result; if (x >= 6 / 29) { result = x * x * x; } else { @@ -17540,9 +17581,9 @@ const LabCS = function LabCSClosure() { return low2 + value * (high2 - low2) / high1; } function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) { - let Ls = src[srcOffset]; - let as = src[srcOffset + 1]; - let bs = src[srcOffset + 2]; + var Ls = src[srcOffset]; + var as = src[srcOffset + 1]; + var bs = src[srcOffset + 2]; if (maxVal !== false) { Ls = decode(Ls, maxVal, 0, 100); as = decode(as, maxVal, cs.amin, cs.amax); @@ -17550,13 +17591,13 @@ const LabCS = function LabCSClosure() { } as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as; bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs; - let M = (Ls + 16) / 116; - let L = M + as / 500; - let N = M - bs / 200; - let X = cs.XW * fn_g(L); - let Y = cs.YW * fn_g(M); - let Z = cs.ZW * fn_g(N); - let r, g, b; + var M = (Ls + 16) / 116; + var L = M + as / 500; + var N = M - bs / 200; + var X = cs.XW * fn_g(L); + var Y = cs.YW * fn_g(M); + var Z = cs.ZW * fn_g(N); + var r, g, b; if (cs.ZW < 1) { r = X * 3.1339 + Y * -1.6170 + Z * -0.4906; g = X * -0.9785 + Y * 1.9160 + Z * 0.0333; @@ -17570,60 +17611,29 @@ const LabCS = function LabCSClosure() { dest[destOffset + 1] = Math.sqrt(g) * 255; dest[destOffset + 2] = Math.sqrt(b) * 255; } - class LabCS extends ColorSpace { - constructor(whitePoint, blackPoint, range) { - super('Lab', 3); - if (!whitePoint) { - throw new _util.FormatError('WhitePoint missing - required for color space Lab'); - } - blackPoint = blackPoint || [0, 0, 0]; - range = range || [-100, 100, -100, 100]; - this.XW = whitePoint[0]; - this.YW = whitePoint[1]; - this.ZW = whitePoint[2]; - this.amin = range[0]; - this.amax = range[1]; - this.bmin = range[2]; - this.bmax = range[3]; - this.XB = blackPoint[0]; - this.YB = blackPoint[1]; - this.ZB = blackPoint[2]; - if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) { - throw new _util.FormatError('Invalid WhitePoint components, no fallback available'); - } - if (this.XB < 0 || this.YB < 0 || this.ZB < 0) { - (0, _util.info)('Invalid BlackPoint, falling back to default'); - this.XB = this.YB = this.ZB = 0; - } - if (this.amin > this.amax || this.bmin > this.bmax) { - (0, _util.info)('Invalid Range, falling back to defaults'); - this.amin = -100; - this.amax = 100; - this.bmin = -100; - this.bmax = 100; - } - } + LabCS.prototype = { + getRgb: ColorSpace.prototype.getRgb, getRgbItem(src, srcOffset, dest, destOffset) { convertToRgb(this, src, srcOffset, false, dest, destOffset); - } + }, getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) { - let maxVal = (1 << bits) - 1; - for (let i = 0; i < count; i++) { + var maxVal = (1 << bits) - 1; + for (var i = 0; i < count; i++) { convertToRgb(this, src, srcOffset, maxVal, dest, destOffset); srcOffset += 3; destOffset += 3 + alpha01; } - } + }, getOutputLength(inputLength, alpha01) { return inputLength * (3 + alpha01) / 3 | 0; - } + }, + isPassthrough: ColorSpace.prototype.isPassthrough, + fillRgb: ColorSpace.prototype.fillRgb, isDefaultDecode(decodeMap) { return true; - } - get usesZeroToOneRange() { - return (0, _util.shadow)(this, 'usesZeroToOneRange', false); - } - } + }, + usesZeroToOneRange: false + }; return LabCS; }(); exports.ColorSpace = ColorSpace; @@ -20059,14 +20069,6 @@ var PartialEvaluator = function PartialEvaluatorClosure() { textContentItem.initialized = false; textContentItem.str.length = 0; } - function isIdenticalSetFont(name, size) { - return textState.font && name === textState.fontName && size === textState.fontSize; - } - function handleBeginText() { - flushTextContentItem(); - textState.textMatrix = _util.IDENTITY_MATRIX.slice(); - textState.textLineMatrix = _util.IDENTITY_MATRIX.slice(); - } function enqueueChunk() { let length = textContent.items.length; if (length > 0) { @@ -20092,7 +20094,6 @@ var PartialEvaluator = function PartialEvaluatorClosure() { var stop, operation = {}, args = []; - let pendingBeginText = false; while (!(stop = timeSlotManager.check())) { args.length = 0; operation.args = args; @@ -20100,27 +20101,14 @@ var PartialEvaluator = function PartialEvaluatorClosure() { break; } textState = stateManager.state; - var fn = operation.fn | 0; + var fn = operation.fn; args = operation.args; var advance, diff; - if (pendingBeginText) { - if (fn === _util.OPS.setFont) { - const fontNameArg = args[0].name, - fontSizeArg = args[1]; - if (isIdenticalSetFont(fontNameArg, fontSizeArg)) { - continue; - } - } - if (fn !== _util.OPS.setTextMatrix) { - handleBeginText(); - } - pendingBeginText = false; - } - switch (fn) { + switch (fn | 0) { case _util.OPS.setFont: var fontNameArg = args[0].name, fontSizeArg = args[1]; - if (isIdenticalSetFont(fontNameArg, fontSizeArg)) { + if (textState.font && fontNameArg === textState.fontName && fontSizeArg === textState.fontSize) { break; } flushTextContentItem(); @@ -20186,11 +20174,9 @@ var PartialEvaluator = function PartialEvaluatorClosure() { textState.wordSpacing = args[0]; break; case _util.OPS.beginText: - if (combineTextItems) { - pendingBeginText = true; - break; - } - handleBeginText(); + flushTextContentItem(); + textState.textMatrix = _util.IDENTITY_MATRIX.slice(); + textState.textLineMatrix = _util.IDENTITY_MATRIX.slice(); break; case _util.OPS.showSpacedText: var items = args[0]; diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index 4258538ee4aa..dd60a0de17d4 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -2,7 +2,7 @@ * @licstart The following is the entire license notice for the * Javascript code in this page * - * Copyright 2018 Mozilla Foundation + * Copyright 2017 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -396,7 +396,7 @@ let PDFViewerApplication = { this.bindWindowEvents(); let appContainer = appConfig.appContainer || document.documentElement; this.l10n.translate(appContainer).then(() => { - this.eventBus.dispatch('localized', { source: this }); + this.eventBus.dispatch('localized'); }); this.initialized = true; }); @@ -480,8 +480,7 @@ let PDFViewerApplication = { let { appConfig } = this; return new Promise((resolve, reject) => { this.overlayManager = new _overlay_manager.OverlayManager(); - const dispatchToDOM = _app_options.AppOptions.get('eventBusDispatchToDOM'); - let eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(dispatchToDOM); + let eventBus = appConfig.eventBus || (0, _dom_events.getGlobalEventBus)(); this.eventBus = eventBus; let pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); pdfRenderingQueue.onIdle = this.cleanup.bind(this); @@ -886,7 +885,6 @@ let PDFViewerApplication = { this.downloadComplete = true; this.loadingBar.hide(); firstPagePromise.then(() => { - this.eventBus.dispatch('documentloaded', { source: this }); this.eventBus.dispatch('documentload', { source: this }); }); }); @@ -962,7 +960,6 @@ let PDFViewerApplication = { scrollMode, spreadMode }); - this.eventBus.dispatch('documentinit', { source: this }); if (!this.isViewerEmbedded) { pdfViewer.focus(); } @@ -1222,16 +1219,13 @@ let PDFViewerApplication = { eventBus.dispatch('resize', { source: window }); }; _boundEvents.windowHashChange = () => { - eventBus.dispatch('hashchange', { - source: window, - hash: document.location.hash.substring(1) - }); + eventBus.dispatch('hashchange', { hash: document.location.hash.substring(1) }); }; _boundEvents.windowBeforePrint = () => { - eventBus.dispatch('beforeprint', { source: window }); + eventBus.dispatch('beforeprint'); }; _boundEvents.windowAfterPrint = () => { - eventBus.dispatch('afterprint', { source: window }); + eventBus.dispatch('afterprint'); }; window.addEventListener('wheel', webViewerWheel); window.addEventListener('click', webViewerClick); @@ -2290,11 +2284,8 @@ let animationStarted = new Promise(function (resolve) { window.requestAnimationFrame(resolve); }); class EventBus { - constructor({ - dispatchToDOM = false - } = {}) { + constructor() { this._listeners = Object.create(null); - this._dispatchToDOM = dispatchToDOM === true; } on(eventName, listener) { let eventListeners = this._listeners[eventName]; @@ -2315,40 +2306,12 @@ class EventBus { dispatch(eventName) { let eventListeners = this._listeners[eventName]; if (!eventListeners || eventListeners.length === 0) { - if (this._dispatchToDOM) { - this._dispatchDOMEvent(eventName); - } return; } let args = Array.prototype.slice.call(arguments, 1); eventListeners.slice(0).forEach(function (listener) { listener.apply(null, args); }); - if (this._dispatchToDOM) { - this._dispatchDOMEvent(eventName, args); - } - } - _dispatchDOMEvent(eventName, args = null) { - if (!this._dispatchToDOM) { - return; - } - const details = Object.create(null); - if (args && args.length > 0) { - const obj = args[0]; - for (let key in obj) { - const value = obj[key]; - if (key === 'source') { - if (value === window || value === document) { - return; - } - continue; - } - details[key] = value; - } - } - const event = document.createEvent('CustomEvent'); - event.initCustomEvent(eventName, true, true, details); - document.dispatchEvent(event); } } function clamp(v, min, max) { @@ -3178,10 +3141,6 @@ const defaultOptions = { value: false, kind: OptionKind.VIEWER }, - eventBusDispatchToDOM: { - value: false, - kind: OptionKind.VIEWER - }, externalLinkRel: { value: 'noopener noreferrer nofollow', kind: OptionKind.VIEWER @@ -3449,13 +3408,12 @@ function attachDOMEventsToEventBus(eventBus) { }); } let globalEventBus = null; -function getGlobalEventBus(dispatchToDOM = false) { - if (!globalEventBus) { - globalEventBus = new _ui_utils.EventBus({ dispatchToDOM }); - if (!dispatchToDOM) { - attachDOMEventsToEventBus(globalEventBus); - } +function getGlobalEventBus() { + if (globalEventBus) { + return globalEventBus; } + globalEventBus = new _ui_utils.EventBus(); + attachDOMEventsToEventBus(globalEventBus); return globalEventBus; } exports.attachDOMEventsToEventBus = attachDOMEventsToEventBus; @@ -5434,19 +5392,19 @@ class PDFPresentationMode { if (contextMenuItems) { contextMenuItems.contextFirstPage.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('firstpage', { source: this }); + this.eventBus.dispatch('firstpage'); }); contextMenuItems.contextLastPage.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('lastpage', { source: this }); + this.eventBus.dispatch('lastpage'); }); contextMenuItems.contextPageRotateCw.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('rotatecw', { source: this }); + this.eventBus.dispatch('rotatecw'); }); contextMenuItems.contextPageRotateCcw.addEventListener('click', () => { this.contextMenuOpen = false; - this.eventBus.dispatch('rotateccw', { source: this }); + this.eventBus.dispatch('rotateccw'); }); } } @@ -8499,16 +8457,16 @@ class Toolbar { let { eventBus, items } = this; let self = this; items.previous.addEventListener('click', function () { - eventBus.dispatch('previouspage', { source: self }); + eventBus.dispatch('previouspage'); }); items.next.addEventListener('click', function () { - eventBus.dispatch('nextpage', { source: self }); + eventBus.dispatch('nextpage'); }); items.zoomIn.addEventListener('click', function () { - eventBus.dispatch('zoomin', { source: self }); + eventBus.dispatch('zoomin'); }); items.zoomOut.addEventListener('click', function () { - eventBus.dispatch('zoomout', { source: self }); + eventBus.dispatch('zoomout'); }); items.pageNumber.addEventListener('click', function () { this.select(); @@ -8529,16 +8487,16 @@ class Toolbar { }); }); items.presentationModeButton.addEventListener('click', function () { - eventBus.dispatch('presentationmode', { source: self }); + eventBus.dispatch('presentationmode'); }); items.openFile.addEventListener('click', function () { - eventBus.dispatch('openfile', { source: self }); + eventBus.dispatch('openfile'); }); items.print.addEventListener('click', function () { - eventBus.dispatch('print', { source: self }); + eventBus.dispatch('print'); }); items.download.addEventListener('click', function () { - eventBus.dispatch('download', { source: self }); + eventBus.dispatch('download'); }); items.scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler; eventBus.on('localized', () => { @@ -9076,7 +9034,6 @@ function getDefaultPreferences() { "sidebarViewOnLoad": 0, "cursorToolOnLoad": 0, "enableWebGL": false, - "eventBusDispatchToDOM": false, "pdfBugEnabled": false, "disableRange": false, "disableStream": false, diff --git a/browser/extensions/pdfjs/moz.yaml b/browser/extensions/pdfjs/moz.yaml index 152fed75c274..d1eeff1ffcfe 100644 --- a/browser/extensions/pdfjs/moz.yaml +++ b/browser/extensions/pdfjs/moz.yaml @@ -20,7 +20,7 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: version 2.0.813 + release: version 2.0.775 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ From b0827c4040c9eda50c2137864a8d3fd9f6c7d869 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Tue, 4 Sep 2018 18:38:19 +0300 Subject: [PATCH 39/80] Backed out 2 changesets (bug 1440879) for build bustages on mozbuild\test\backend. CLOSED TREE Backed out changeset 93892cfed015 (bug 1440879) Backed out changeset 71d569322700 (bug 1440879) --- config/moz.build | 4 ---- python/mozbuild/mozbuild/backend/common.py | 9 --------- python/mozbuild/mozbuild/frontend/data.py | 3 ++- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/config/moz.build b/config/moz.build index ce6297393373..d9c28fe54d05 100644 --- a/config/moz.build +++ b/config/moz.build @@ -47,10 +47,6 @@ if CONFIG['WRAP_STL_INCLUDES']: stl_compiler = 'msvc' if stl_compiler: - # Note that the 'stl_wrappers' folder is known to the build system as - # containing generated files; if this is changed here then the code in - # GeneratedFile.__init__ in python/mozbuild/mozbuild/frontend/data.py - # might need to be updated accordingly as well. template_file = SRCDIR + '/%s-stl-wrapper.template.h' % stl_compiler output_dir = '../dist/stl_wrappers' # We have to use a sentinel file as the first file because the diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py index 25f96113a683..949bbee30eb8 100644 --- a/python/mozbuild/mozbuild/backend/common.py +++ b/python/mozbuild/mozbuild/backend/common.py @@ -28,7 +28,6 @@ from mozbuild.frontend.data import ( Exports, FinalTargetPreprocessedFiles, FinalTargetFiles, - GeneratedFile, GeneratedSources, GnProjectData, HostLibrary, @@ -170,14 +169,6 @@ class CommonBackend(BuildBackend): self._handle_generated_sources(obj.files) return False - elif isinstance(obj, GeneratedFile): - if obj.required_for_compile: - for f in obj.required_for_compile: - fullpath = ObjDirPath(obj._context, '!' + f).full_path - relpath = mozpath.relpath(fullpath, obj._context.config.topobjdir) - self._handle_generated_sources([relpath]) - return False - elif isinstance(obj, Exports): objdir_files = [f.full_path for path, files in obj.files.walk() for f in files if isinstance(f, ObjDirPath)] if objdir_files: diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index b737b5ea2e1f..6bdf7ce543ce 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -1168,8 +1168,9 @@ class GeneratedFile(ContextDerived): '.inc', '.py', '.rs', + 'new', # 'new' is an output from make-stl-wrappers.py ) - self.required_for_compile = [f for f in self.outputs if f.endswith(suffixes) or 'stl_wrappers/' in f] + self.required_for_compile = any(f.endswith(suffixes) for f in self.outputs) class ChromeManifestEntry(ContextDerived): From 952bbf4613d8679c454a318ed060a920fb0c1a51 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:42:34 +0200 Subject: [PATCH 40/80] Backout all patches of bug 1308436, wrong patches have landed. --HG-- extra : rebase_source : 0ad64a5fbbeeedc1015218c6a27a03cfaf972aa7 --- .../webaudioeditor/test/doc_bug_1112378.html | 4 +- dom/bindings/Errors.msg | 5 - dom/media/webaudio/AudioEventTimeline.cpp | 35 +- dom/media/webaudio/AudioEventTimeline.h | 75 +-- dom/media/webaudio/AudioParam.h | 24 +- .../webaudio/gtest/TestAudioEventTimeline.cpp | 441 ++++++++++++++++++ dom/media/webaudio/gtest/moz.build | 15 + dom/media/webaudio/moz.build | 2 + dom/media/webaudio/test/mochitest.ini | 2 + .../test_audioParamSetCurveAtTimeTwice.html | 68 +++ ..._audioParamSetCurveAtTimeZeroDuration.html | 57 +++ .../audioparam-exceptional-values.html.ini | 70 +++ .../audioparam-method-chaining.html.ini | 8 +- ...dioparam-setValueCurve-exceptions.html.ini | 46 ++ .../event-insertion.html.ini | 19 +- .../audioparam-exceptional-values.html | 7 +- .../audioparam-setValueCurve-exceptions.html | 57 +-- .../event-insertion.html | 6 +- 18 files changed, 795 insertions(+), 146 deletions(-) create mode 100644 dom/media/webaudio/gtest/TestAudioEventTimeline.cpp create mode 100644 dom/media/webaudio/gtest/moz.build create mode 100644 dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html create mode 100644 dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html create mode 100644 testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini create mode 100644 testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini diff --git a/devtools/client/webaudioeditor/test/doc_bug_1112378.html b/devtools/client/webaudioeditor/test/doc_bug_1112378.html index d16cbe6e9dec..910a89f5145f 100644 --- a/devtools/client/webaudioeditor/test/doc_bug_1112378.html +++ b/devtools/client/webaudioeditor/test/doc_bug_1112378.html @@ -14,7 +14,7 @@ "use strict"; const ctx = new AudioContext(); - const osc = ctx.createStereoPanner(); + const osc = ctx.createOscillator(); function throwError() { try { @@ -34,7 +34,7 @@ function throwDOMException() { try { - osc.channelCount = 3; + osc.frequency.setValueAtTime(0, -1); } catch (e) { return { lineNumber: e.lineNumber, diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index 4d9eb79d7f0e..5f3c579ae3cf 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -106,8 +106,3 @@ MSG_DEF(MSG_CACHE_OPEN_FAILED, 0, JSEXN_TYPEERR, "CacheStorage.open() failed to MSG_DEF(MSG_MATRIX_INIT_LENGTH_WRONG, 1, JSEXN_TYPEERR, "Matrix init sequence must have a length of 6 or 16 (actual value: {0})") MSG_DEF(MSG_INVALID_MEDIA_VIDEO_CONFIGURATION, 0, JSEXN_TYPEERR, "Invalid VideoConfiguration.") MSG_DEF(MSG_INVALID_MEDIA_AUDIO_CONFIGURATION, 0, JSEXN_TYPEERR, "Invalid AudioConfiguration.") -MSG_DEF(MSG_INVALID_CURVE_DURATION_ERROR, 0, JSEXN_RANGEERR, "The curve duration for SetValueCurve must be strictly positive.") -MSG_DEF(MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR, 0, JSEXN_RANGEERR, "The start time for an AudioParam method must be positive.") -MSG_DEF(MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR, 0, JSEXN_RANGEERR, "The end time for an AudioParam method must be positive.") -MSG_DEF(MSG_INVALID_AUDIOPARAM_EXPONENTIAL_VALUE_ERROR, 0, JSEXN_RANGEERR, "The value passed to exponentialCurveToValueAtTime must be positive.") -MSG_DEF(MSG_INVALID_AUDIOPARAM_EXPONENTIAL_CONSTANT_ERROR, 0, JSEXN_RANGEERR, "The exponential constant passed to setTargetAtTime must be positive.") diff --git a/dom/media/webaudio/AudioEventTimeline.cpp b/dom/media/webaudio/AudioEventTimeline.cpp index 377901a342c9..9f8b705e56b4 100644 --- a/dom/media/webaudio/AudioEventTimeline.cpp +++ b/dom/media/webaudio/AudioEventTimeline.cpp @@ -221,37 +221,22 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, return mValue; } - // If this event is a curve event, this returns the end time of the curve. - // Otherwise, this returns the time of the event. auto TimeOf = [](const AudioTimelineEvent* aEvent) -> TimeType { - if (aEvent->mType == AudioTimelineEvent::SetValueCurve) { - return aEvent->template Time() + aEvent->mDuration; - } return aEvent->template Time(); }; - // Value for an event. For a ValueCurve event, this is the value of the last - // element of the curve. - auto ValueOf = [](const AudioTimelineEvent* aEvent) -> float { - if (aEvent->mType == AudioTimelineEvent::SetValueCurve) { - return aEvent->mCurve[aEvent->mCurveLength - 1]; - } - return aEvent->mValue; - }; - // SetTarget nodes can be handled no matter what their next node is (if // they have one) if (aPrevious->mType == AudioTimelineEvent::SetTarget) { return ExponentialApproach(TimeOf(aPrevious), - mLastComputedValue, ValueOf(aPrevious), + mLastComputedValue, aPrevious->mValue, aPrevious->mTimeConstant, aTime); } // SetValueCurve events can be handled no matter what their next node is - // (if they have one), when aTime is in the curve region. - if (aPrevious->mType == AudioTimelineEvent::SetValueCurve && - aTime <= aPrevious->template Time() + aPrevious->mDuration) { - return ExtractValueFromCurve(aPrevious->template Time(), + // (if they have one) + if (aPrevious->mType == AudioTimelineEvent::SetValueCurve) { + return ExtractValueFromCurve(TimeOf(aPrevious), aPrevious->mCurve, aPrevious->mCurveLength, aPrevious->mDuration, aTime); } @@ -265,7 +250,7 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, // The value will be constant after the last event return aPrevious->mValue; case AudioTimelineEvent::SetValueCurve: - return ExtractValueFromCurve(aPrevious->template Time(), + return ExtractValueFromCurve(TimeOf(aPrevious), aPrevious->mCurve, aPrevious->mCurveLength, aPrevious->mDuration, aTime); case AudioTimelineEvent::SetTarget: @@ -284,15 +269,15 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, switch (aNext->mType) { case AudioTimelineEvent::LinearRamp: return LinearInterpolate(TimeOf(aPrevious), - ValueOf(aPrevious), + aPrevious->mValue, TimeOf(aNext), - ValueOf(aNext), aTime); + aNext->mValue, aTime); case AudioTimelineEvent::ExponentialRamp: return ExponentialInterpolate(TimeOf(aPrevious), - ValueOf(aPrevious), + aPrevious->mValue, TimeOf(aNext), - ValueOf(aNext), aTime); + aNext->mValue, aTime); case AudioTimelineEvent::SetValueAtTime: case AudioTimelineEvent::SetTarget: @@ -313,7 +298,7 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, // value is constant. return aPrevious->mValue; case AudioTimelineEvent::SetValueCurve: - return ExtractValueFromCurve(aPrevious->template Time(), + return ExtractValueFromCurve(TimeOf(aPrevious), aPrevious->mCurve, aPrevious->mCurveLength, aPrevious->mDuration, aTime); case AudioTimelineEvent::SetTarget: diff --git a/dom/media/webaudio/AudioEventTimeline.h b/dom/media/webaudio/AudioEventTimeline.h index 2fda791f14d7..aeb4ef0a5a52 100644 --- a/dom/media/webaudio/AudioEventTimeline.h +++ b/dom/media/webaudio/AudioEventTimeline.h @@ -11,7 +11,6 @@ #include "mozilla/Assertions.h" #include "mozilla/FloatingPoint.h" #include "mozilla/PodOperations.h" -#include "mozilla/ErrorResult.h" #include "MainThreadUtils.h" #include "nsTArray.h" @@ -117,6 +116,13 @@ inline int64_t AudioTimelineEvent::Time() const return mTimeInTicks; } +/** + * Some methods in this class will be instantiated with different ErrorResult + * template arguments for testing and production code. + * + * ErrorResult is a type which satisfies the following: + * - Implements a Throw() method taking an nsresult argument, representing an error code. + */ class AudioEventTimeline { public: @@ -126,6 +132,7 @@ public: mLastComputedValue(aDefaultValue) { } + template bool ValidateEvent(AudioTimelineEvent& aEvent, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); @@ -135,52 +142,51 @@ public: }; // Validate the event itself - if (!WebAudioUtils::IsTimeValid(TimeOf(aEvent))) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); - return false; - } - if (!WebAudioUtils::IsTimeValid(aEvent.mTimeConstant)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_EXPONENTIAL_CONSTANT_ERROR>(); + if (!WebAudioUtils::IsTimeValid(TimeOf(aEvent)) || + !WebAudioUtils::IsTimeValid(aEvent.mTimeConstant)) { + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return false; } if (aEvent.mType == AudioTimelineEvent::SetValueCurve) { if (!aEvent.mCurve || !aEvent.mCurveLength) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return false; - } - if (aEvent.mCurveLength < 2) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return false; - } - if (aEvent.mDuration <= 0) { - aRv.template ThrowRangeError(); + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return false; } } - MOZ_ASSERT(IsValid(aEvent.mValue) && IsValid(aEvent.mDuration)); + bool timeAndValueValid = IsValid(aEvent.mValue) && + IsValid(aEvent.mDuration); + if (!timeAndValueValid) { + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + return false; + } - // Make sure that new events don't fall within the duration of a + // Make sure that non-curve events don't fall within the duration of a // curve event. for (unsigned i = 0; i < mEvents.Length(); ++i) { if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve && + !(aEvent.mType == AudioTimelineEvent::SetValueCurve && + TimeOf(aEvent) == TimeOf(mEvents[i])) && TimeOf(mEvents[i]) <= TimeOf(aEvent) && - TimeOf(mEvents[i]) + mEvents[i].mDuration > TimeOf(aEvent)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + TimeOf(mEvents[i]) + mEvents[i].mDuration >= TimeOf(aEvent)) { + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return false; } } - // Make sure that new curve events don't fall in a range which includes other + // Make sure that curve events don't fall in a range which includes other // events. if (aEvent.mType == AudioTimelineEvent::SetValueCurve) { for (unsigned i = 0; i < mEvents.Length(); ++i) { - if (TimeOf(aEvent) < TimeOf(mEvents[i]) && - TimeOf(aEvent) + aEvent.mDuration >= TimeOf(mEvents[i])) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + // In case we have two curve at the same time + if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve && + TimeOf(mEvents[i]) == TimeOf(aEvent)) { + continue; + } + if (TimeOf(mEvents[i]) > TimeOf(aEvent) && + TimeOf(mEvents[i]) < TimeOf(aEvent) + aEvent.mDuration) { + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return false; } } @@ -189,8 +195,7 @@ public: // Make sure that invalid values are not used for exponential curves if (aEvent.mType == AudioTimelineEvent::ExponentialRamp) { if (aEvent.mValue <= 0.f) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_EXPONENTIAL_VALUE_ERROR>(); + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return false; } const AudioTimelineEvent* previousEvent = GetPreviousEvent(TimeOf(aEvent)); @@ -214,14 +219,19 @@ public: { for (unsigned i = 0; i < mEvents.Length(); ++i) { if (aEvent.template Time() == mEvents[i].template Time()) { - // If two events happen at the same time, have them in chronological - // order of insertion. + if (aEvent.mType == mEvents[i].mType) { + // If times and types are equal, replace the event + mEvents.ReplaceElementAt(i, aEvent); + } else { + // Otherwise, place the element after the last event of another type do { ++i; } while (i < mEvents.Length() && aEvent.mType != mEvents[i].mType && aEvent.template Time() == mEvents[i].template Time()); mEvents.InsertElementAt(i, aEvent); + } + return; } // Otherwise, place the event right after the latest existing event if (aEvent.template Time() < mEvents[i].template Time()) { @@ -260,6 +270,7 @@ public: } } + template void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::SetValueAtTime, aStartTime, aValue); @@ -269,6 +280,7 @@ public: } } + template void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::LinearRamp, aEndTime, aValue); @@ -278,6 +290,7 @@ public: } } + template void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::ExponentialRamp, aEndTime, aValue); @@ -287,6 +300,7 @@ public: } } + template void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::SetTarget, aStartTime, aTarget, aTimeConstant); @@ -296,6 +310,7 @@ public: } } + template void SetValueCurveAtTime(const float* aValues, uint32_t aValuesLength, double aStartTime, double aDuration, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength); diff --git a/dom/media/webaudio/AudioParam.h b/dom/media/webaudio/AudioParam.h index fa2d0de6bf47..29d486173dd8 100644 --- a/dom/media/webaudio/AudioParam.h +++ b/dom/media/webaudio/AudioParam.h @@ -51,16 +51,13 @@ public: ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return this; } aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime()); EventInsertionHelper(aRv, AudioTimelineEvent::SetValueCurve, - aStartTime, 0.0f, - 0.0f, aDuration, aValues.Elements(), + aStartTime, 0.0f, 0.0f, aDuration, aValues.Elements(), aValues.Length()); - return this; } @@ -83,8 +80,7 @@ public: AudioParam* SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return this; } aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime()); @@ -98,8 +94,7 @@ public: ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aEndTime)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR>(); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return this; } aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime()); @@ -111,8 +106,7 @@ public: ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aEndTime)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR>(); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return this; } aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime()); @@ -126,8 +120,7 @@ public: { if (!WebAudioUtils::IsTimeValid(aStartTime) || !WebAudioUtils::IsTimeValid(aTimeConstant)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return this; } aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime()); @@ -141,8 +134,7 @@ public: AudioParam* CancelScheduledValues(double aStartTime, ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { - aRv.template ThrowRangeError< - MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return this; } @@ -227,7 +219,7 @@ private: AudioTimelineEvent::Type aType, double aTime, float aValue, double aTimeConstant = 0.0, - double aDuration = 0.0, + float aDuration = 0.0, const float* aCurve = nullptr, uint32_t aCurveLength = 0) { diff --git a/dom/media/webaudio/gtest/TestAudioEventTimeline.cpp b/dom/media/webaudio/gtest/TestAudioEventTimeline.cpp new file mode 100644 index 000000000000..dcb45d77543a --- /dev/null +++ b/dom/media/webaudio/gtest/TestAudioEventTimeline.cpp @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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/. */ + +#include "AudioEventTimeline.h" +#include +#include +#include "gtest/gtest.h" + +// Mock the MediaStream class +namespace mozilla { +class MediaStream +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream) +private: + ~MediaStream() { + }; +}; +} + +using namespace mozilla; +using namespace mozilla::dom; +using std::numeric_limits; + +// Some simple testing primitives +void ok(bool val, const char* msg) +{ + if (!val) { + fprintf(stderr, "failure: %s", msg); + } + ASSERT_TRUE(val); +} + +namespace std { + +template +basic_ostream >& +operator<<(basic_ostream >& os, nsresult rv) +{ + os << static_cast(rv); + return os; +} + +} // namespace std + +template +void is(const T& a, const U& b, const char* msg) +{ + std::stringstream ss; + ss << msg << ", Got: " << a << ", expected: " << b << std::endl; + ok(a == b, ss.str().c_str()); +} + +template <> +void is(const float& a, const float& b, const char* msg) +{ + // stupidly high, since we mostly care about the correctness of the algorithm + const float kEpsilon = 0.00001f; + + std::stringstream ss; + ss << msg << ", Got: " << a << ", expected: " << b << std::endl; + ok(fabsf(a - b) < kEpsilon, ss.str().c_str()); +} + +class ErrorResultMock +{ +public: + ErrorResultMock() + : mRv(NS_OK) + { + } + void Throw(nsresult aRv) + { + mRv = aRv; + } + + operator nsresult() const + { + return mRv; + } + + ErrorResultMock& operator=(nsresult aRv) + { + mRv = aRv; + return *this; + } + +private: + nsresult mRv; +}; + +typedef AudioEventTimeline Timeline; + +TEST(AudioEventTimeline, SpecExample) +{ + // First, run the basic tests + Timeline timeline(10.0f); + is(timeline.Value(), 10.0f, "Correct default value returned"); + + ErrorResultMock rv; + + uint32_t curveLength = 44100; + float* curve = new float[curveLength]; + for (uint32_t i = 0; i < curveLength; ++i) { + curve[i] = sin(M_PI * i / float(curveLength)); + } + + // This test is copied from the example in the Web Audio spec + const double t0 = 0.0, + t1 = 0.1, + t2 = 0.2, + t3 = 0.3, + t4 = 0.4, + t5 = 0.6, + t6 = 0.7, + t7 = 1.0; + timeline.SetValueAtTime(0.2f, t0, rv); + is(rv, NS_OK, "SetValueAtTime succeeded"); + timeline.SetValueAtTime(0.3f, t1, rv); + is(rv, NS_OK, "SetValueAtTime succeeded"); + timeline.SetValueAtTime(0.4f, t2, rv); + is(rv, NS_OK, "SetValueAtTime succeeded"); + timeline.LinearRampToValueAtTime(1.0f, t3, rv); + is(rv, NS_OK, "LinearRampToValueAtTime succeeded"); + timeline.LinearRampToValueAtTime(0.15f, t4, rv); + is(rv, NS_OK, "LinearRampToValueAtTime succeeded"); + timeline.ExponentialRampToValueAtTime(0.75f, t5, rv); + is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded"); + timeline.ExponentialRampToValueAtTime(0.05f, t6, rv); + is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded"); + timeline.SetValueCurveAtTime(curve, curveLength, t6, t7 - t6, rv); + is(rv, NS_OK, "SetValueCurveAtTime succeeded"); + + is(timeline.GetValueAtTime(0.0), 0.2f, "Correct value"); + is(timeline.GetValueAtTime(0.05), 0.2f, "Correct value"); + is(timeline.GetValueAtTime(0.1), 0.3f, "Correct value"); + is(timeline.GetValueAtTime(0.15), 0.3f, "Correct value"); + is(timeline.GetValueAtTime(0.2), 0.4f, "Correct value"); + is(timeline.GetValueAtTime(0.25), (0.4f + 1.0f) / 2, "Correct value"); + is(timeline.GetValueAtTime(0.3), 1.0f, "Correct value"); + is(timeline.GetValueAtTime(0.35), (1.0f + 0.15f) / 2, "Correct value"); + is(timeline.GetValueAtTime(0.4), 0.15f, "Correct value"); + is(timeline.GetValueAtTime(0.45), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value"); + is(timeline.GetValueAtTime(0.5), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value"); + is(timeline.GetValueAtTime(0.55), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value"); + is(timeline.GetValueAtTime(0.6), 0.75f, "Correct value"); + is(timeline.GetValueAtTime(0.65), (0.75f * powf(0.05f / 0.75f, 0.5f)), "Correct value"); + is(timeline.GetValueAtTime(0.7), 0.0f, "Correct value"); + is(timeline.GetValueAtTime(0.85), 1.0f, "Correct value"); + is(timeline.GetValueAtTime(1.0), curve[curveLength - 1], "Correct value"); + + delete[] curve; +} + +TEST(AudioEventTimeline, InvalidEvents) +{ + static_assert(numeric_limits::has_quiet_NaN, "Platform must have a quiet NaN"); + const float NaN = numeric_limits::quiet_NaN(); + const float Infinity = numeric_limits::infinity(); + Timeline timeline(10.0f); + + float curve[] = { -1.0f, 0.0f, 1.0f }; + + ErrorResultMock rv; + + timeline.SetValueAtTime(NaN, 0.1, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueAtTime(Infinity, 0.1, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueAtTime(-Infinity, 0.1, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.LinearRampToValueAtTime(NaN, 0.2, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.LinearRampToValueAtTime(Infinity, 0.2, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.LinearRampToValueAtTime(-Infinity, 0.2, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.ExponentialRampToValueAtTime(NaN, 0.3, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.ExponentialRampToValueAtTime(Infinity, 0.3, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.ExponentialRampToValueAtTime(-Infinity, 0.4, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.ExponentialRampToValueAtTime(0, 0.5, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetTargetAtTime(NaN, 0.4, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetTargetAtTime(Infinity, 0.4, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetTargetAtTime(-Infinity, 0.4, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetTargetAtTime(0.4f, NaN, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetTargetAtTime(0.4f, Infinity, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetTargetAtTime(0.4f, -Infinity, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(nullptr, 0, 1.0, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), NaN, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), Infinity, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), -Infinity, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, NaN, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, Infinity, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, -Infinity, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); +} + +TEST(AudioEventTimeline, EventReplacement) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + is(timeline.GetEventCount(), 0u, "No events yet"); + timeline.SetValueAtTime(10.0f, 0.1, rv); + is(timeline.GetEventCount(), 1u, "One event scheduled now"); + timeline.SetValueAtTime(20.0f, 0.1, rv); + is(rv, NS_OK, "Event scheduling should be successful"); + is(timeline.GetEventCount(), 1u, "Event should be replaced"); + is(timeline.GetValueAtTime(0.1), 20.0f, "The first event should be overwritten"); + timeline.LinearRampToValueAtTime(30.0f, 0.1, rv); + is(rv, NS_OK, "Event scheduling should be successful"); + is(timeline.GetEventCount(), 2u, "Different event type should be appended"); + is(timeline.GetValueAtTime(0.1), 30.0f, "The first event should be overwritten"); +} + +TEST(AudioEventTimeline, EventRemoval) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetValueAtTime(10.0f, 0.1, rv); + timeline.SetValueAtTime(15.0f, 0.15, rv); + timeline.SetValueAtTime(20.0f, 0.2, rv); + timeline.LinearRampToValueAtTime(30.0f, 0.3, rv); + is(timeline.GetEventCount(), 4u, "Should have three events initially"); + timeline.CancelScheduledValues(0.4); + is(timeline.GetEventCount(), 4u, "Trying to delete past the end of the array should have no effect"); + timeline.CancelScheduledValues(0.3); + is(timeline.GetEventCount(), 3u, "Should successfully delete one event"); + timeline.CancelScheduledValues(0.12); + is(timeline.GetEventCount(), 1u, "Should successfully delete two events"); + timeline.CancelAllEvents(); + ok(timeline.HasSimpleValue(), "No event should remain scheduled"); +} + +TEST(AudioEventTimeline, BeforeFirstEventSetValue) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetValueAtTime(20.0f, 1.0, rv); + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); +} + +TEST(AudioEventTimeline, BeforeFirstEventSetTarget) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); +} + +TEST(AudioEventTimeline, BeforeFirstEventLinearRamp) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.LinearRampToValueAtTime(20.0f, 1.0, rv); + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); +} + +TEST(AudioEventTimeline, BeforeFirstEventExponentialRamp) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv); + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); +} + +TEST(AudioEventTimeline, AfterLastValueEvent) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetValueAtTime(20.0f, 1.0, rv); + is(timeline.GetValueAtTime(1.5), 20.0f, "Return the last value after the last SetValue event"); +} + +TEST(AudioEventTimeline, AfterLastTargetValueEvent) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); + is(timeline.GetValueAtTime(10.), (20.f + (10.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after the last SetTarget event based on the curve"); +} + +TEST(AudioEventTimeline, AfterLastTargetValueEventWithValueSet) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetValue(50.f); + timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); + + // When using SetTargetValueAtTime, Timeline become stateful: the value for + // time t may depend on the time t-1, so we can't just query the value at a + // time and get the right value. We have to call GetValueAtTime for the + // previous times. + for (double i = 0.0; i < 9.99; i+=0.01) { + timeline.GetValueAtTime(i); + } + + is(timeline.GetValueAtTime(10.), (20.f + (50.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after SetValue and the last SetTarget event based on the curve"); +} + +TEST(AudioEventTimeline, Value) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + is(timeline.Value(), 10.0f, "value should initially match the default value"); + timeline.SetValue(20.0f); + is(timeline.Value(), 20.0f, "Should be able to set the value"); + timeline.SetValueAtTime(20.0f, 1.0, rv); + // TODO: The following check needs to change when we compute the value based on the current time of the context + is(timeline.Value(), 20.0f, "TODO..."); + timeline.SetValue(30.0f); + is(timeline.Value(), 20.0f, "Should not be able to set the value"); +} + +TEST(AudioEventTimeline, LinearRampAtZero) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.LinearRampToValueAtTime(20.0f, 0.0, rv); + is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0"); +} + +TEST(AudioEventTimeline, ExponentialRampAtZero) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.ExponentialRampToValueAtTime(20.0f, 0.0, rv); + is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0"); +} + +TEST(AudioEventTimeline, LinearRampAtSameTime) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetValueAtTime(5.0f, 1.0, rv); + timeline.LinearRampToValueAtTime(20.0f, 1.0, rv); + is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); +} + +TEST(AudioEventTimeline, ExponentialRampAtSameTime) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetValueAtTime(5.0f, 1.0, rv); + timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv); + is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); +} + +TEST(AudioEventTimeline, SetTargetZeroTimeConstant) +{ + Timeline timeline(10.0f); + + ErrorResultMock rv; + + timeline.SetTargetAtTime(20.0f, 1.0, 0.0, rv); + is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); +} + +TEST(AudioEventTimeline, ExponentialInvalidPreviousZeroValue) +{ + Timeline timeline(0.f); + + ErrorResultMock rv; + + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.SetValue(1.f); + rv = NS_OK; + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); + is(rv, NS_OK, "Should succeed this time"); + timeline.CancelScheduledValues(0.0); + is(timeline.GetEventCount(), 0u, "Should have no events scheduled"); + rv = NS_OK; + timeline.SetValueAtTime(0.f, 0.5, rv); + is(rv, NS_OK, "Should succeed"); + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); + timeline.CancelScheduledValues(0.0); + is(timeline.GetEventCount(), 0u, "Should have no events scheduled"); + rv = NS_OK; + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); + is(rv, NS_OK, "Should succeed this time"); +} + +TEST(AudioEventTimeline, SettingValueCurveTwice) +{ + Timeline timeline(0.f); + float curve[] = { -1.0f, 0.0f, 1.0f }; + + ErrorResultMock rv; + + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 0.0f, 0.3f, rv); + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 0.0f, 0.3f, rv); + is(rv, NS_OK, "SetValueCurveAtTime succeeded"); +} + diff --git a/dom/media/webaudio/gtest/moz.build b/dom/media/webaudio/gtest/moz.build new file mode 100644 index 000000000000..2cc13b038dc2 --- /dev/null +++ b/dom/media/webaudio/gtest/moz.build @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +UNIFIED_SOURCES += [ + 'TestAudioEventTimeline.cpp', +] + +LOCAL_INCLUDES += [ + '..', +] + +FINAL_LIBRARY = 'xul-gtest' diff --git a/dom/media/webaudio/moz.build b/dom/media/webaudio/moz.build index 485eb1a8f7c0..a2ce3623c90b 100644 --- a/dom/media/webaudio/moz.build +++ b/dom/media/webaudio/moz.build @@ -9,6 +9,8 @@ with Files('*'): DIRS += ['blink'] +TEST_DIRS += ['gtest'] + MOCHITEST_MANIFESTS += [ 'test/blink/mochitest.ini', 'test/mochitest.ini', diff --git a/dom/media/webaudio/test/mochitest.ini b/dom/media/webaudio/test/mochitest.ini index a840aa06bfe4..68dd83c12e3b 100644 --- a/dom/media/webaudio/test/mochitest.ini +++ b/dom/media/webaudio/test/mochitest.ini @@ -73,6 +73,8 @@ tags=capturestream [test_audioParamGain.html] [test_audioParamLinearRamp.html] [test_audioParamSetCurveAtTime.html] +[test_audioParamSetCurveAtTimeTwice.html] +[test_audioParamSetCurveAtTimeZeroDuration.html] [test_audioParamSetTargetAtTime.html] [test_audioParamSetTargetAtTimeZeroTimeConstant.html] [test_audioParamSetValueAtTime.html] diff --git a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html new file mode 100644 index 000000000000..0f976380e077 --- /dev/null +++ b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html @@ -0,0 +1,68 @@ + + + + Test AudioParam.setValueCurveAtTime twice + + + + + +
+
+
+ + diff --git a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html new file mode 100644 index 000000000000..174c15c6fe3b --- /dev/null +++ b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html @@ -0,0 +1,57 @@ + + + + Test AudioParam.linearRampToValue + + + + + +
+
+
+ + diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini new file mode 100644 index 000000000000..094a59dd09db --- /dev/null +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini @@ -0,0 +1,70 @@ +[audioparam-exceptional-values.html] + [X gain.gain.setValueAtTime(1,-1) threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X gain.gain.linearRampToValueAtTime(1,-1) threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(1,-1) threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X gain.gain.setTargetAtTime(1,-1,1) threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X gain.gain.setTargetAtTime(1,1,-1) threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X gain.gain.setValueCurveAtTime([0,0,0\],-1,1) threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X gain.gain.setValueCurveAtTime([0,0,0\],1,-1) did not throw an exception.] + expected: FAIL + + [X gain.gain.setValueCurveAtTime(curve, 1, 0) did not throw an exception.] + expected: FAIL + + [< [special cases 1\] 8 out of 8 assertions were failed.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(0,1) threw "SyntaxError" instead of RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(-1e-100,1) threw "SyntaxError" instead of RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(1e-100,1) threw "SyntaxError" instead of RangeError.] + expected: FAIL + + [< [special cases 2\] 3 out of 3 assertions were failed.] + expected: FAIL + + [# AUDIT TASK RUNNER FINISHED: 2 out of 6 tasks were failed.] + expected: FAIL + + [X gain.gain.setTargetAtTime(1,-1,1) threw "NotSupportedError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(-1e-100,1) threw "SyntaxError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.linearRampToValueAtTime(1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(0,1) threw "SyntaxError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.setValueCurveAtTime([0,0,0\],-1,1) threw "NotSupportedError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.setValueAtTime(1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(1e-100,1) threw "SyntaxError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.exponentialRampToValueAtTime(1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] + expected: FAIL + + [X gain.gain.setTargetAtTime(1,1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] + expected: FAIL + diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini index 8fd28847a7ed..45f6de7bb97d 100644 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini @@ -1,8 +1,14 @@ [audioparam-method-chaining.html] + [X Calling setValueAtTime() with a negative end time threw "NotSupportedError" instead of RangeError.] + expected: FAIL + + [X Calling exponentialRampToValueAtTime() with a zero target value threw "SyntaxError" instead of RangeError.] + expected: FAIL + [X The gain value of the second gain node is not equal to 0.5. Got 1.] expected: FAIL - [< [invalid-operation\] 1 out of 4 assertions were failed.] + [< [invalid-operation\] 3 out of 4 assertions were failed.] expected: FAIL [# AUDIT TASK RUNNER FINISHED: 1 out of 3 tasks were failed.] diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini new file mode 100644 index 000000000000..29cf7a1a8fdc --- /dev/null +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini @@ -0,0 +1,46 @@ +[audioparam-setValueCurve-exceptions.html] + [X setValueAtTime(1, 0.018750000000000003) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X linearRampToValueAtTime(1, 0.018750000000000003) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X exponentialRampToValueAtTime(1, 0.018750000000000003) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X setTargetAtTime(1, 0.018750000000000003, 1) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [< [setValueCurve\] 4 out of 6 assertions were failed.] + expected: FAIL + + [X setValueCurveAtTime(curve, 0.00625, 0.01) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X setValueCurveAtTime(curve, 0.018750000000000003, 0.01) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X setValueCurveAtTime(curve, 0.03125, 0.01) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X setValueCurveAtTime(curve, 0.043750000000000004, 0.01) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [X setValueCurveAtTime(curve, 0.031415926535897934, 0.01) threw "SyntaxError" instead of NotSupportedError.] + expected: FAIL + + [< [automations\] 5 out of 13 assertions were failed.] + expected: FAIL + + [X setValueCurveAtTime([\], 0, 0.01) threw "SyntaxError" instead of InvalidStateError.] + expected: FAIL + + [X setValueCurveAtTime([1\], 0, 0.01) did not throw an exception.] + expected: FAIL + + [< [curve lengths\] 2 out of 3 assertions were failed.] + expected: FAIL + + [# AUDIT TASK RUNNER FINISHED: 3 out of 5 tasks were failed.] + expected: FAIL + diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini index 3164e8d3f47c..73896a59e0d2 100644 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini @@ -1,10 +1,25 @@ [event-insertion.html] - [< [Insert same event at same time\] 1 out of 12 assertions were failed.] + [X setValueCurveAtTime([98,99\], 0.0234375, 0.0078125) incorrectly threw TypeError: "Argument 1 of AudioParam.setValueCurveAtTime does not implement interface Float32Array.".] expected: FAIL - [X Output at frame 384 (time 0.0234375) is not equal to 3. Got 98.] + [X setValueCurveAtTime([3,4\], 0.0234375, 0.0078125) incorrectly threw TypeError: "Argument 1 of AudioParam.setValueCurveAtTime does not implement interface Float32Array.".] + expected: FAIL + + [X Output at frame 512 (time 0.03125) is not equal to 4. Got 3.] + expected: FAIL + + [< [Insert same event at same time\] 3 out of 12 assertions were failed.] expected: FAIL [# AUDIT TASK RUNNER FINISHED: 1 out of 4 tasks were failed.] expected: FAIL + [X Output at frame 384 (time 0.0234375) is not equal to 3. Got 98.] + expected: FAIL + + [X Output at frame 512 (time 0.03125) is not equal to 4. Got 99.] + expected: FAIL + + [< [Insert same event at same time\] 2 out of 12 assertions were failed.] + expected: FAIL + diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html index 982731d33843..c928b3dc165a 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html @@ -174,16 +174,11 @@ }, ]); - // Two final tests for setValueCurve: duration must be strictly - // positive. + // One final test for setValueCurve: duration can't be 0. should( () => gain.gain.setValueCurveAtTime(curve, 1, 0), 'gain.gain.setValueCurveAtTime(curve, 1, 0)') .throw(RangeError); - should( - () => gain.gain.setValueCurveAtTime(curve, 1, -1), - 'gain.gain.setValueCurveAtTime(curve, 1, -1)') - .throw(RangeError); task.done(); }); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html index 16975f1c7c8f..31405ebfcd2a 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html @@ -30,7 +30,7 @@ let curveStartTime = 0.1 * testDurationSec; let duration = 0.1 * testDurationSec; - // Some time that is known to be during the setValueCurveTime interval. + // Some time that is known to during the setValueCurveTime interval. let automationTime = curveStartTime + duration / 2; should( @@ -286,61 +286,6 @@ task.done(); }); - audit.define('curve overlap', (task, should) => { - let context = - new OfflineAudioContext(1, testDurationFrames, sampleRate); - let g = context.createGain(); - let startTime = 5; - let startTimeLater = 10; - let startTimeEarlier = 2.5; - let curveDuration = 10; - let curveDurationShorter = 5; - let curve = [1, 2, 3]; - - // An initial curve event - should( - () => { - g.gain.setValueCurveAtTime(curve, startTime, curveDuration); - }, - `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`) - .notThrow(); - - // Check that an exception is thrown when trying to overlap two curves, - // in various ways - - // Same start time and end time (curve exactly overlapping) - should( - () => { - g.gain.setValueCurveAtTime(curve, startTime, curveDuration); - }, - `second g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`) - .throw('NotSupportedError'); - // Same start time, shorter end time - should( - () => { - g.gain.setValueCurveAtTime(curve, startTime, curveDurationShorter); - }, - `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDurationShorter})`) - .throw('NotSupportedError'); - // Earlier start time, end time after the start time an another curve - should( - () => { - g.gain.setValueCurveAtTime(curve, startTimeEarlier, curveDuration); - }, - `g.gain.setValueCurveAtTime([${curve}], ${startTimeEarlier}, ${curveDuration})`) - .throw('NotSupportedError'); - // Start time after the start time of the other curve, but earlier that - // its end. - should( - () => { - g.gain.setValueCurveAtTime(curve, startTimeLater, curveDuration); - }, - `g.gain.setValueCurveAtTime([${curve}], ${startTimeLater}, ${curveDuration})`) - .throw('NotSupportedError'); - - task.done(); - }); - audit.define('curve lengths', (task, should) => { let context = new OfflineAudioContext(1, testDurationFrames, sampleRate); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html index 688d0478235e..eab77c494d11 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html @@ -30,8 +30,8 @@ // An array of tests to be done. Each entry specifies the event // type and the event time. The events are inserted in the order - // given (in |values|), and the second event should be inserted - // after the first one, as required by the spec. + // given (in |values|), and the second event should replace the + // first, as required by the spec. let testCases = [ { event: 'setValueAtTime', @@ -57,7 +57,7 @@ { event: 'setValueCurveAtTime', frame: 3 * RENDER_QUANTUM_FRAMES, - values: [[3, 4]], + values: [[98, 99], [3, 4]], extraArgs: RENDER_QUANTUM_FRAMES / context.sampleRate, outputTestFrame: 4 * RENDER_QUANTUM_FRAMES, expectedOutputValue: 4 From 36e6573cce3f89f64accec8332c03cb2d714f1d3 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:43:01 +0200 Subject: [PATCH 41/80] Bug 1308436 - Don't convert the curve duration from double to float in the EventInsertionHelper to avoid losing precision. r=karlt --HG-- extra : rebase_source : f0ccc616f6ad0098302538f3d62f147acacdcb74 --- dom/media/webaudio/AudioParam.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/webaudio/AudioParam.h b/dom/media/webaudio/AudioParam.h index 29d486173dd8..1ecadc8482f1 100644 --- a/dom/media/webaudio/AudioParam.h +++ b/dom/media/webaudio/AudioParam.h @@ -219,7 +219,7 @@ private: AudioTimelineEvent::Type aType, double aTime, float aValue, double aTimeConstant = 0.0, - float aDuration = 0.0, + double aDuration = 0.0, const float* aCurve = nullptr, uint32_t aCurveLength = 0) { From d5456e3c941b91f79e52eb41f0e2c2dcbd08984a Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:43:33 +0200 Subject: [PATCH 42/80] Bug 1308436 - Add a test case for a negative curve duration in audioparam-exceptional-values.html. r=karlt --HG-- extra : rebase_source : 0aabee13942925d1333e187838e2f320479a610a --- .../audioparam-exceptional-values.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html index c928b3dc165a..982731d33843 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html @@ -174,11 +174,16 @@ }, ]); - // One final test for setValueCurve: duration can't be 0. + // Two final tests for setValueCurve: duration must be strictly + // positive. should( () => gain.gain.setValueCurveAtTime(curve, 1, 0), 'gain.gain.setValueCurveAtTime(curve, 1, 0)') .throw(RangeError); + should( + () => gain.gain.setValueCurveAtTime(curve, 1, -1), + 'gain.gain.setValueCurveAtTime(curve, 1, -1)') + .throw(RangeError); task.done(); }); From d3e189242f6ad1f3f9d28ae0acbedb3516f9b768 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:55:38 +0200 Subject: [PATCH 43/80] Bug 1308436 - Remove TestAudioEventTimeline.cpp. r=karlt --HG-- extra : rebase_source : 3a4bd55abdb58bb1a0064cd27826fadfbfa869d5 --- dom/media/webaudio/AudioEventTimeline.h | 14 +- .../webaudio/gtest/TestAudioEventTimeline.cpp | 441 ------------------ dom/media/webaudio/gtest/moz.build | 15 - dom/media/webaudio/moz.build | 2 - 4 files changed, 1 insertion(+), 471 deletions(-) delete mode 100644 dom/media/webaudio/gtest/TestAudioEventTimeline.cpp delete mode 100644 dom/media/webaudio/gtest/moz.build diff --git a/dom/media/webaudio/AudioEventTimeline.h b/dom/media/webaudio/AudioEventTimeline.h index aeb4ef0a5a52..ceac4c2272a8 100644 --- a/dom/media/webaudio/AudioEventTimeline.h +++ b/dom/media/webaudio/AudioEventTimeline.h @@ -11,6 +11,7 @@ #include "mozilla/Assertions.h" #include "mozilla/FloatingPoint.h" #include "mozilla/PodOperations.h" +#include "mozilla/ErrorResult.h" #include "MainThreadUtils.h" #include "nsTArray.h" @@ -116,13 +117,6 @@ inline int64_t AudioTimelineEvent::Time() const return mTimeInTicks; } -/** - * Some methods in this class will be instantiated with different ErrorResult - * template arguments for testing and production code. - * - * ErrorResult is a type which satisfies the following: - * - Implements a Throw() method taking an nsresult argument, representing an error code. - */ class AudioEventTimeline { public: @@ -132,7 +126,6 @@ public: mLastComputedValue(aDefaultValue) { } - template bool ValidateEvent(AudioTimelineEvent& aEvent, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); @@ -270,7 +263,6 @@ public: } } - template void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::SetValueAtTime, aStartTime, aValue); @@ -280,7 +272,6 @@ public: } } - template void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::LinearRamp, aEndTime, aValue); @@ -290,7 +281,6 @@ public: } } - template void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::ExponentialRamp, aEndTime, aValue); @@ -300,7 +290,6 @@ public: } } - template void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::SetTarget, aStartTime, aTarget, aTimeConstant); @@ -310,7 +299,6 @@ public: } } - template void SetValueCurveAtTime(const float* aValues, uint32_t aValuesLength, double aStartTime, double aDuration, ErrorResult& aRv) { AudioTimelineEvent event(AudioTimelineEvent::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues, aValuesLength); diff --git a/dom/media/webaudio/gtest/TestAudioEventTimeline.cpp b/dom/media/webaudio/gtest/TestAudioEventTimeline.cpp deleted file mode 100644 index dcb45d77543a..000000000000 --- a/dom/media/webaudio/gtest/TestAudioEventTimeline.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#include "AudioEventTimeline.h" -#include -#include -#include "gtest/gtest.h" - -// Mock the MediaStream class -namespace mozilla { -class MediaStream -{ - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream) -private: - ~MediaStream() { - }; -}; -} - -using namespace mozilla; -using namespace mozilla::dom; -using std::numeric_limits; - -// Some simple testing primitives -void ok(bool val, const char* msg) -{ - if (!val) { - fprintf(stderr, "failure: %s", msg); - } - ASSERT_TRUE(val); -} - -namespace std { - -template -basic_ostream >& -operator<<(basic_ostream >& os, nsresult rv) -{ - os << static_cast(rv); - return os; -} - -} // namespace std - -template -void is(const T& a, const U& b, const char* msg) -{ - std::stringstream ss; - ss << msg << ", Got: " << a << ", expected: " << b << std::endl; - ok(a == b, ss.str().c_str()); -} - -template <> -void is(const float& a, const float& b, const char* msg) -{ - // stupidly high, since we mostly care about the correctness of the algorithm - const float kEpsilon = 0.00001f; - - std::stringstream ss; - ss << msg << ", Got: " << a << ", expected: " << b << std::endl; - ok(fabsf(a - b) < kEpsilon, ss.str().c_str()); -} - -class ErrorResultMock -{ -public: - ErrorResultMock() - : mRv(NS_OK) - { - } - void Throw(nsresult aRv) - { - mRv = aRv; - } - - operator nsresult() const - { - return mRv; - } - - ErrorResultMock& operator=(nsresult aRv) - { - mRv = aRv; - return *this; - } - -private: - nsresult mRv; -}; - -typedef AudioEventTimeline Timeline; - -TEST(AudioEventTimeline, SpecExample) -{ - // First, run the basic tests - Timeline timeline(10.0f); - is(timeline.Value(), 10.0f, "Correct default value returned"); - - ErrorResultMock rv; - - uint32_t curveLength = 44100; - float* curve = new float[curveLength]; - for (uint32_t i = 0; i < curveLength; ++i) { - curve[i] = sin(M_PI * i / float(curveLength)); - } - - // This test is copied from the example in the Web Audio spec - const double t0 = 0.0, - t1 = 0.1, - t2 = 0.2, - t3 = 0.3, - t4 = 0.4, - t5 = 0.6, - t6 = 0.7, - t7 = 1.0; - timeline.SetValueAtTime(0.2f, t0, rv); - is(rv, NS_OK, "SetValueAtTime succeeded"); - timeline.SetValueAtTime(0.3f, t1, rv); - is(rv, NS_OK, "SetValueAtTime succeeded"); - timeline.SetValueAtTime(0.4f, t2, rv); - is(rv, NS_OK, "SetValueAtTime succeeded"); - timeline.LinearRampToValueAtTime(1.0f, t3, rv); - is(rv, NS_OK, "LinearRampToValueAtTime succeeded"); - timeline.LinearRampToValueAtTime(0.15f, t4, rv); - is(rv, NS_OK, "LinearRampToValueAtTime succeeded"); - timeline.ExponentialRampToValueAtTime(0.75f, t5, rv); - is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded"); - timeline.ExponentialRampToValueAtTime(0.05f, t6, rv); - is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded"); - timeline.SetValueCurveAtTime(curve, curveLength, t6, t7 - t6, rv); - is(rv, NS_OK, "SetValueCurveAtTime succeeded"); - - is(timeline.GetValueAtTime(0.0), 0.2f, "Correct value"); - is(timeline.GetValueAtTime(0.05), 0.2f, "Correct value"); - is(timeline.GetValueAtTime(0.1), 0.3f, "Correct value"); - is(timeline.GetValueAtTime(0.15), 0.3f, "Correct value"); - is(timeline.GetValueAtTime(0.2), 0.4f, "Correct value"); - is(timeline.GetValueAtTime(0.25), (0.4f + 1.0f) / 2, "Correct value"); - is(timeline.GetValueAtTime(0.3), 1.0f, "Correct value"); - is(timeline.GetValueAtTime(0.35), (1.0f + 0.15f) / 2, "Correct value"); - is(timeline.GetValueAtTime(0.4), 0.15f, "Correct value"); - is(timeline.GetValueAtTime(0.45), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value"); - is(timeline.GetValueAtTime(0.5), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value"); - is(timeline.GetValueAtTime(0.55), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value"); - is(timeline.GetValueAtTime(0.6), 0.75f, "Correct value"); - is(timeline.GetValueAtTime(0.65), (0.75f * powf(0.05f / 0.75f, 0.5f)), "Correct value"); - is(timeline.GetValueAtTime(0.7), 0.0f, "Correct value"); - is(timeline.GetValueAtTime(0.85), 1.0f, "Correct value"); - is(timeline.GetValueAtTime(1.0), curve[curveLength - 1], "Correct value"); - - delete[] curve; -} - -TEST(AudioEventTimeline, InvalidEvents) -{ - static_assert(numeric_limits::has_quiet_NaN, "Platform must have a quiet NaN"); - const float NaN = numeric_limits::quiet_NaN(); - const float Infinity = numeric_limits::infinity(); - Timeline timeline(10.0f); - - float curve[] = { -1.0f, 0.0f, 1.0f }; - - ErrorResultMock rv; - - timeline.SetValueAtTime(NaN, 0.1, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueAtTime(Infinity, 0.1, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueAtTime(-Infinity, 0.1, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.LinearRampToValueAtTime(NaN, 0.2, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.LinearRampToValueAtTime(Infinity, 0.2, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.LinearRampToValueAtTime(-Infinity, 0.2, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.ExponentialRampToValueAtTime(NaN, 0.3, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.ExponentialRampToValueAtTime(Infinity, 0.3, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.ExponentialRampToValueAtTime(-Infinity, 0.4, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.ExponentialRampToValueAtTime(0, 0.5, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetTargetAtTime(NaN, 0.4, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetTargetAtTime(Infinity, 0.4, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetTargetAtTime(-Infinity, 0.4, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetTargetAtTime(0.4f, NaN, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetTargetAtTime(0.4f, Infinity, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetTargetAtTime(0.4f, -Infinity, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(nullptr, 0, 1.0, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), NaN, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), Infinity, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), -Infinity, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, NaN, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, Infinity, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, -Infinity, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); -} - -TEST(AudioEventTimeline, EventReplacement) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - is(timeline.GetEventCount(), 0u, "No events yet"); - timeline.SetValueAtTime(10.0f, 0.1, rv); - is(timeline.GetEventCount(), 1u, "One event scheduled now"); - timeline.SetValueAtTime(20.0f, 0.1, rv); - is(rv, NS_OK, "Event scheduling should be successful"); - is(timeline.GetEventCount(), 1u, "Event should be replaced"); - is(timeline.GetValueAtTime(0.1), 20.0f, "The first event should be overwritten"); - timeline.LinearRampToValueAtTime(30.0f, 0.1, rv); - is(rv, NS_OK, "Event scheduling should be successful"); - is(timeline.GetEventCount(), 2u, "Different event type should be appended"); - is(timeline.GetValueAtTime(0.1), 30.0f, "The first event should be overwritten"); -} - -TEST(AudioEventTimeline, EventRemoval) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetValueAtTime(10.0f, 0.1, rv); - timeline.SetValueAtTime(15.0f, 0.15, rv); - timeline.SetValueAtTime(20.0f, 0.2, rv); - timeline.LinearRampToValueAtTime(30.0f, 0.3, rv); - is(timeline.GetEventCount(), 4u, "Should have three events initially"); - timeline.CancelScheduledValues(0.4); - is(timeline.GetEventCount(), 4u, "Trying to delete past the end of the array should have no effect"); - timeline.CancelScheduledValues(0.3); - is(timeline.GetEventCount(), 3u, "Should successfully delete one event"); - timeline.CancelScheduledValues(0.12); - is(timeline.GetEventCount(), 1u, "Should successfully delete two events"); - timeline.CancelAllEvents(); - ok(timeline.HasSimpleValue(), "No event should remain scheduled"); -} - -TEST(AudioEventTimeline, BeforeFirstEventSetValue) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetValueAtTime(20.0f, 1.0, rv); - is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); -} - -TEST(AudioEventTimeline, BeforeFirstEventSetTarget) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); - is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); -} - -TEST(AudioEventTimeline, BeforeFirstEventLinearRamp) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.LinearRampToValueAtTime(20.0f, 1.0, rv); - is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); -} - -TEST(AudioEventTimeline, BeforeFirstEventExponentialRamp) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv); - is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); -} - -TEST(AudioEventTimeline, AfterLastValueEvent) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetValueAtTime(20.0f, 1.0, rv); - is(timeline.GetValueAtTime(1.5), 20.0f, "Return the last value after the last SetValue event"); -} - -TEST(AudioEventTimeline, AfterLastTargetValueEvent) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); - is(timeline.GetValueAtTime(10.), (20.f + (10.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after the last SetTarget event based on the curve"); -} - -TEST(AudioEventTimeline, AfterLastTargetValueEventWithValueSet) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetValue(50.f); - timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); - - // When using SetTargetValueAtTime, Timeline become stateful: the value for - // time t may depend on the time t-1, so we can't just query the value at a - // time and get the right value. We have to call GetValueAtTime for the - // previous times. - for (double i = 0.0; i < 9.99; i+=0.01) { - timeline.GetValueAtTime(i); - } - - is(timeline.GetValueAtTime(10.), (20.f + (50.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after SetValue and the last SetTarget event based on the curve"); -} - -TEST(AudioEventTimeline, Value) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - is(timeline.Value(), 10.0f, "value should initially match the default value"); - timeline.SetValue(20.0f); - is(timeline.Value(), 20.0f, "Should be able to set the value"); - timeline.SetValueAtTime(20.0f, 1.0, rv); - // TODO: The following check needs to change when we compute the value based on the current time of the context - is(timeline.Value(), 20.0f, "TODO..."); - timeline.SetValue(30.0f); - is(timeline.Value(), 20.0f, "Should not be able to set the value"); -} - -TEST(AudioEventTimeline, LinearRampAtZero) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.LinearRampToValueAtTime(20.0f, 0.0, rv); - is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0"); -} - -TEST(AudioEventTimeline, ExponentialRampAtZero) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.ExponentialRampToValueAtTime(20.0f, 0.0, rv); - is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0"); -} - -TEST(AudioEventTimeline, LinearRampAtSameTime) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetValueAtTime(5.0f, 1.0, rv); - timeline.LinearRampToValueAtTime(20.0f, 1.0, rv); - is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); -} - -TEST(AudioEventTimeline, ExponentialRampAtSameTime) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetValueAtTime(5.0f, 1.0, rv); - timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv); - is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); -} - -TEST(AudioEventTimeline, SetTargetZeroTimeConstant) -{ - Timeline timeline(10.0f); - - ErrorResultMock rv; - - timeline.SetTargetAtTime(20.0f, 1.0, 0.0, rv); - is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); -} - -TEST(AudioEventTimeline, ExponentialInvalidPreviousZeroValue) -{ - Timeline timeline(0.f); - - ErrorResultMock rv; - - timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.SetValue(1.f); - rv = NS_OK; - timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); - is(rv, NS_OK, "Should succeed this time"); - timeline.CancelScheduledValues(0.0); - is(timeline.GetEventCount(), 0u, "Should have no events scheduled"); - rv = NS_OK; - timeline.SetValueAtTime(0.f, 0.5, rv); - is(rv, NS_OK, "Should succeed"); - timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); - is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); - timeline.CancelScheduledValues(0.0); - is(timeline.GetEventCount(), 0u, "Should have no events scheduled"); - rv = NS_OK; - timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); - is(rv, NS_OK, "Should succeed this time"); -} - -TEST(AudioEventTimeline, SettingValueCurveTwice) -{ - Timeline timeline(0.f); - float curve[] = { -1.0f, 0.0f, 1.0f }; - - ErrorResultMock rv; - - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 0.0f, 0.3f, rv); - timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 0.0f, 0.3f, rv); - is(rv, NS_OK, "SetValueCurveAtTime succeeded"); -} - diff --git a/dom/media/webaudio/gtest/moz.build b/dom/media/webaudio/gtest/moz.build deleted file mode 100644 index 2cc13b038dc2..000000000000 --- a/dom/media/webaudio/gtest/moz.build +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -UNIFIED_SOURCES += [ - 'TestAudioEventTimeline.cpp', -] - -LOCAL_INCLUDES += [ - '..', -] - -FINAL_LIBRARY = 'xul-gtest' diff --git a/dom/media/webaudio/moz.build b/dom/media/webaudio/moz.build index a2ce3623c90b..485eb1a8f7c0 100644 --- a/dom/media/webaudio/moz.build +++ b/dom/media/webaudio/moz.build @@ -9,8 +9,6 @@ with Files('*'): DIRS += ['blink'] -TEST_DIRS += ['gtest'] - MOCHITEST_MANIFESTS += [ 'test/blink/mochitest.ini', 'test/mochitest.ini', From c9104891cb5a424b2eba10d109896707028f28b8 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:44:03 +0200 Subject: [PATCH 44/80] Bug 1308436 - Rework the AudioParam event insertion algorithm to be spec compliant, and fix the exception types and values. r=karlt --HG-- extra : rebase_source : 48227c953316a45c81be3ed39366133096de43a9 --- dom/bindings/Errors.msg | 5 ++ dom/media/webaudio/AudioEventTimeline.h | 87 +++++++++++-------------- dom/media/webaudio/AudioParam.h | 19 ++++-- 3 files changed, 57 insertions(+), 54 deletions(-) diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index 5f3c579ae3cf..2a882b59cedb 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -106,3 +106,8 @@ MSG_DEF(MSG_CACHE_OPEN_FAILED, 0, JSEXN_TYPEERR, "CacheStorage.open() failed to MSG_DEF(MSG_MATRIX_INIT_LENGTH_WRONG, 1, JSEXN_TYPEERR, "Matrix init sequence must have a length of 6 or 16 (actual value: {0})") MSG_DEF(MSG_INVALID_MEDIA_VIDEO_CONFIGURATION, 0, JSEXN_TYPEERR, "Invalid VideoConfiguration.") MSG_DEF(MSG_INVALID_MEDIA_AUDIO_CONFIGURATION, 0, JSEXN_TYPEERR, "Invalid AudioConfiguration.") +MSG_DEF(MSG_INVALID_CURVE_DURATION_ERROR, 0, JSEXN_RANGEERR, "The curve duration for setValueCurveAtTime must be strictly positive.") +MSG_DEF(MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR, 0, JSEXN_RANGEERR, "The start time for an AudioParam method must be non-negative.") +MSG_DEF(MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR, 0, JSEXN_RANGEERR, "The end time for an AudioParam method must be non-negative.") +MSG_DEF(MSG_INVALID_AUDIOPARAM_EXPONENTIAL_VALUE_ERROR, 0, JSEXN_RANGEERR, "The value passed to exponentialRampToValueAtTime must be positive.") +MSG_DEF(MSG_INVALID_AUDIOPARAM_EXPONENTIAL_CONSTANT_ERROR, 0, JSEXN_RANGEERR, "The exponential constant passed to setTargetAtTime must be non-negative.") diff --git a/dom/media/webaudio/AudioEventTimeline.h b/dom/media/webaudio/AudioEventTimeline.h index ceac4c2272a8..8cb47552fd01 100644 --- a/dom/media/webaudio/AudioEventTimeline.h +++ b/dom/media/webaudio/AudioEventTimeline.h @@ -131,55 +131,52 @@ public: MOZ_ASSERT(NS_IsMainThread()); auto TimeOf = [](const AudioTimelineEvent& aEvent) -> double { - return aEvent.template Time(); + return aEvent.Time(); }; // Validate the event itself - if (!WebAudioUtils::IsTimeValid(TimeOf(aEvent)) || - !WebAudioUtils::IsTimeValid(aEvent.mTimeConstant)) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + if (!WebAudioUtils::IsTimeValid(TimeOf(aEvent))) { + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); + return false; + } + if (!WebAudioUtils::IsTimeValid(aEvent.mTimeConstant)) { + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_EXPONENTIAL_CONSTANT_ERROR>(); return false; } if (aEvent.mType == AudioTimelineEvent::SetValueCurve) { - if (!aEvent.mCurve || !aEvent.mCurveLength) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + if (!aEvent.mCurve || aEvent.mCurveLength < 2) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return false; + } + if (aEvent.mDuration <= 0) { + aRv.ThrowRangeError(); return false; } } - bool timeAndValueValid = IsValid(aEvent.mValue) && - IsValid(aEvent.mDuration); - if (!timeAndValueValid) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); - return false; - } + MOZ_ASSERT(IsValid(aEvent.mValue) && IsValid(aEvent.mDuration)); - // Make sure that non-curve events don't fall within the duration of a + // Make sure that new events don't fall within the duration of a // curve event. for (unsigned i = 0; i < mEvents.Length(); ++i) { if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve && - !(aEvent.mType == AudioTimelineEvent::SetValueCurve && - TimeOf(aEvent) == TimeOf(mEvents[i])) && TimeOf(mEvents[i]) <= TimeOf(aEvent) && - TimeOf(mEvents[i]) + mEvents[i].mDuration >= TimeOf(aEvent)) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + TimeOf(mEvents[i]) + mEvents[i].mDuration > TimeOf(aEvent)) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return false; } } - // Make sure that curve events don't fall in a range which includes other - // events. + // Make sure that new curve events don't fall in a range which includes + // other events. if (aEvent.mType == AudioTimelineEvent::SetValueCurve) { for (unsigned i = 0; i < mEvents.Length(); ++i) { - // In case we have two curve at the same time - if (mEvents[i].mType == AudioTimelineEvent::SetValueCurve && - TimeOf(mEvents[i]) == TimeOf(aEvent)) { - continue; - } - if (TimeOf(mEvents[i]) > TimeOf(aEvent) && - TimeOf(mEvents[i]) < TimeOf(aEvent) + aEvent.mDuration) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + if (TimeOf(aEvent) < TimeOf(mEvents[i]) && + TimeOf(aEvent) + aEvent.mDuration > TimeOf(mEvents[i])) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return false; } } @@ -188,7 +185,8 @@ public: // Make sure that invalid values are not used for exponential curves if (aEvent.mType == AudioTimelineEvent::ExponentialRamp) { if (aEvent.mValue <= 0.f) { - aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_EXPONENTIAL_VALUE_ERROR>(); return false; } const AudioTimelineEvent* previousEvent = GetPreviousEvent(TimeOf(aEvent)); @@ -211,23 +209,18 @@ public: void InsertEvent(const AudioTimelineEvent& aEvent) { for (unsigned i = 0; i < mEvents.Length(); ++i) { - if (aEvent.template Time() == mEvents[i].template Time()) { - if (aEvent.mType == mEvents[i].mType) { - // If times and types are equal, replace the event - mEvents.ReplaceElementAt(i, aEvent); - } else { - // Otherwise, place the element after the last event of another type - do { - ++i; - } while (i < mEvents.Length() && - aEvent.mType != mEvents[i].mType && - aEvent.template Time() == mEvents[i].template Time()); - mEvents.InsertElementAt(i, aEvent); - } + if (aEvent.Time() == mEvents[i].Time()) { + // If two events happen at the same time, have them in chronological + // order of insertion. + do { + ++i; + } while (i < mEvents.Length() && aEvent.mType != mEvents[i].mType && + aEvent.Time() == mEvents[i].Time()); + mEvents.InsertElementAt(i, aEvent); return; } // Otherwise, place the event right after the latest existing event - if (aEvent.template Time() < mEvents[i].template Time()) { + if (aEvent.Time() < mEvents[i].Time()) { mEvents.InsertElementAt(i, aEvent); return; } @@ -311,12 +304,12 @@ public: void CancelScheduledValues(TimeType aStartTime) { for (unsigned i = 0; i < mEvents.Length(); ++i) { - if (mEvents[i].template Time() >= aStartTime) { + if (mEvents[i].Time() >= aStartTime) { #ifdef DEBUG // Sanity check: the array should be sorted, so all of the following // events should have a time greater than aStartTime too. for (unsigned j = i + 1; j < mEvents.Length(); ++j) { - MOZ_ASSERT(mEvents[j].template Time() >= aStartTime); + MOZ_ASSERT(mEvents[j].Time() >= aStartTime); } #endif mEvents.TruncateLength(i); @@ -367,13 +360,11 @@ public: template void CleanupEventsOlderThan(TimeType aTime) { - while (mEvents.Length() > 1 && - aTime > mEvents[1].template Time()) { + while (mEvents.Length() > 1 && aTime > mEvents[1].Time()) { if (mEvents[1].mType == AudioTimelineEvent::SetTarget) { mLastComputedValue = GetValuesAtTimeHelperInternal( - mEvents[1].template Time(), - &mEvents[0], nullptr); + mEvents[1].Time(), &mEvents[0], nullptr); } mEvents.RemoveElementAt(0); diff --git a/dom/media/webaudio/AudioParam.h b/dom/media/webaudio/AudioParam.h index 1ecadc8482f1..781feb7692e3 100644 --- a/dom/media/webaudio/AudioParam.h +++ b/dom/media/webaudio/AudioParam.h @@ -51,13 +51,15 @@ public: ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); return this; } aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime()); EventInsertionHelper(aRv, AudioTimelineEvent::SetValueCurve, aStartTime, 0.0f, 0.0f, aDuration, aValues.Elements(), aValues.Length()); + return this; } @@ -80,7 +82,8 @@ public: AudioParam* SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); return this; } aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime()); @@ -94,7 +97,8 @@ public: ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aEndTime)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR>(); return this; } aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime()); @@ -106,7 +110,8 @@ public: ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aEndTime)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_END_TIME_ERROR>(); return this; } aEndTime = std::max(aEndTime, GetParentObject()->CurrentTime()); @@ -120,7 +125,8 @@ public: { if (!WebAudioUtils::IsTimeValid(aStartTime) || !WebAudioUtils::IsTimeValid(aTimeConstant)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); return this; } aStartTime = std::max(aStartTime, GetParentObject()->CurrentTime()); @@ -134,7 +140,8 @@ public: AudioParam* CancelScheduledValues(double aStartTime, ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + aRv.ThrowRangeError< + MSG_INVALID_AUDIOPARAM_METHOD_START_TIME_ERROR>(); return this; } From 95dcc68529100ee2b0998c5afde0d9ee1450b80d Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:46:11 +0200 Subject: [PATCH 45/80] Bug 1308436 - Adjust the AudioParam processing algorithm to match the spec. r=karlt --HG-- extra : rebase_source : 13f085ac8e7d4e313a4fbe1996a3b1cb5f81ea38 --- dom/media/webaudio/AudioEventTimeline.cpp | 67 ++++++++++++++++------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/dom/media/webaudio/AudioEventTimeline.cpp b/dom/media/webaudio/AudioEventTimeline.cpp index 9f8b705e56b4..39b36566ca1f 100644 --- a/dom/media/webaudio/AudioEventTimeline.cpp +++ b/dom/media/webaudio/AudioEventTimeline.cpp @@ -116,7 +116,7 @@ AudioEventTimeline::GetValuesAtTimeHelper(TimeType aTime, float* aBuffer, MOZ_ASSERT(aSize); auto TimeOf = [](const AudioTimelineEvent& aEvent) -> TimeType { - return aEvent.template Time(); + return aEvent.Time(); }; size_t eventIndex = 0; @@ -186,7 +186,7 @@ AudioEventTimeline::GetValuesAtTimeHelper(int64_t aTime, float* aBuffer, template float AudioEventTimeline::GetValueAtTimeOfEvent(const AudioTimelineEvent* aNext) { - TimeType time = aNext->template Time(); + TimeType time = aNext->Time(); switch (aNext->mType) { case AudioTimelineEvent::SetTarget: // SetTarget nodes can be handled no matter what their next node is @@ -221,24 +221,43 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, return mValue; } + // If this event is a curve event, this returns the end time of the curve. + // Otherwise, this returns the time of the event. auto TimeOf = [](const AudioTimelineEvent* aEvent) -> TimeType { - return aEvent->template Time(); + if (aEvent->mType == AudioTimelineEvent::SetValueCurve) { + return aEvent->Time() + aEvent->mDuration; + } + return aEvent->Time(); + }; + + // Value for an event. For a ValueCurve event, this is the value of the last + // element of the curve. + auto ValueOf = [](const AudioTimelineEvent* aEvent) -> float { + if (aEvent->mType == AudioTimelineEvent::SetValueCurve) { + return aEvent->mCurve[aEvent->mCurveLength - 1]; + } + return aEvent->mValue; }; // SetTarget nodes can be handled no matter what their next node is (if // they have one) if (aPrevious->mType == AudioTimelineEvent::SetTarget) { return ExponentialApproach(TimeOf(aPrevious), - mLastComputedValue, aPrevious->mValue, - aPrevious->mTimeConstant, aTime); + mLastComputedValue, + ValueOf(aPrevious), + aPrevious->mTimeConstant, + aTime); } // SetValueCurve events can be handled no matter what their next node is - // (if they have one) - if (aPrevious->mType == AudioTimelineEvent::SetValueCurve) { - return ExtractValueFromCurve(TimeOf(aPrevious), - aPrevious->mCurve, aPrevious->mCurveLength, - aPrevious->mDuration, aTime); + // (if they have one), when aTime is in the curve region. + if (aPrevious->mType == AudioTimelineEvent::SetValueCurve && + aTime <= aPrevious->Time() + aPrevious->mDuration) { + return ExtractValueFromCurve(aPrevious->Time(), + aPrevious->mCurve, + aPrevious->mCurveLength, + aPrevious->mDuration, + aTime); } // If the requested time is after all of the existing events @@ -250,9 +269,11 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, // The value will be constant after the last event return aPrevious->mValue; case AudioTimelineEvent::SetValueCurve: - return ExtractValueFromCurve(TimeOf(aPrevious), - aPrevious->mCurve, aPrevious->mCurveLength, - aPrevious->mDuration, aTime); + return ExtractValueFromCurve(aPrevious->Time(), + aPrevious->mCurve, + aPrevious->mCurveLength, + aPrevious->mDuration, + aTime); case AudioTimelineEvent::SetTarget: MOZ_FALLTHROUGH_ASSERT("AudioTimelineEvent::SetTarget"); case AudioTimelineEvent::SetValue: @@ -269,15 +290,17 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, switch (aNext->mType) { case AudioTimelineEvent::LinearRamp: return LinearInterpolate(TimeOf(aPrevious), - aPrevious->mValue, + ValueOf(aPrevious), TimeOf(aNext), - aNext->mValue, aTime); + ValueOf(aNext), + aTime); case AudioTimelineEvent::ExponentialRamp: return ExponentialInterpolate(TimeOf(aPrevious), - aPrevious->mValue, + ValueOf(aPrevious), TimeOf(aNext), - aNext->mValue, aTime); + ValueOf(aNext), + aTime); case AudioTimelineEvent::SetValueAtTime: case AudioTimelineEvent::SetTarget: @@ -298,9 +321,11 @@ AudioEventTimeline::GetValuesAtTimeHelperInternal(TimeType aTime, // value is constant. return aPrevious->mValue; case AudioTimelineEvent::SetValueCurve: - return ExtractValueFromCurve(TimeOf(aPrevious), - aPrevious->mCurve, aPrevious->mCurveLength, - aPrevious->mDuration, aTime); + return ExtractValueFromCurve(aPrevious->Time(), + aPrevious->mCurve, + aPrevious->mCurveLength, + aPrevious->mDuration, + aTime); case AudioTimelineEvent::SetTarget: MOZ_FALLTHROUGH_ASSERT("AudioTimelineEvent::SetTarget"); case AudioTimelineEvent::SetValue: @@ -328,7 +353,7 @@ AudioEventTimeline::GetPreviousEvent(double aTime) const const AudioTimelineEvent* next = nullptr; auto TimeOf = [](const AudioTimelineEvent& aEvent) -> double { - return aEvent.template Time(); + return aEvent.Time(); }; bool bailOut = false; From 337f79b5afbd62d942676c638cedd4b7d0511b97 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:49:22 +0200 Subject: [PATCH 46/80] Bug 1308436 - Fix typo in audioparam-setValueCurve-exceptions.html. r=karlt --HG-- extra : rebase_source : a27ff4cdb6df70a395e466b8e3dd6c5c4f2210c0 --- testing/web-platform/meta/MANIFEST.json | 4 ++-- .../audioparam-setValueCurve-exceptions.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 4a46dd10e5a4..83b6a77cfcd8 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -650293,7 +650293,7 @@ "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html": [ - "16975f1c7c8f8079916e4fd4f166b63ad9fa686a", + "a7182dba59b8c3d21b1a6b4dd7ac2d3bf997ab33", "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html": [ @@ -650313,7 +650313,7 @@ "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/event-insertion.html": [ - "688d0478235e202859c7939eef65ad383f7a4f36", + "eab77c494d1161083f1fe73376492b177355995f", "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet.https.html": [ diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html index 31405ebfcd2a..a7182dba59b8 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html @@ -30,7 +30,7 @@ let curveStartTime = 0.1 * testDurationSec; let duration = 0.1 * testDurationSec; - // Some time that is known to during the setValueCurveTime interval. + // Some time that is known to be during the setValueCurveTime interval. let automationTime = curveStartTime + duration / 2; should( From bc962c7382136de35c1d0a5d8460f9affd4de3f9 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:49:45 +0200 Subject: [PATCH 47/80] Bug 1308436 - Remove test_audioParamSetCurveAtTimeZeroDuration.html. r=karlt --HG-- extra : rebase_source : f55b68c787c43564a24640c0847572ca6ea6ae78 --- dom/media/webaudio/test/mochitest.ini | 1 - ..._audioParamSetCurveAtTimeZeroDuration.html | 57 ------------------- 2 files changed, 58 deletions(-) delete mode 100644 dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html diff --git a/dom/media/webaudio/test/mochitest.ini b/dom/media/webaudio/test/mochitest.ini index 68dd83c12e3b..105105a94dd9 100644 --- a/dom/media/webaudio/test/mochitest.ini +++ b/dom/media/webaudio/test/mochitest.ini @@ -74,7 +74,6 @@ tags=capturestream [test_audioParamLinearRamp.html] [test_audioParamSetCurveAtTime.html] [test_audioParamSetCurveAtTimeTwice.html] -[test_audioParamSetCurveAtTimeZeroDuration.html] [test_audioParamSetTargetAtTime.html] [test_audioParamSetTargetAtTimeZeroTimeConstant.html] [test_audioParamSetValueAtTime.html] diff --git a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html deleted file mode 100644 index 174c15c6fe3b..000000000000 --- a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeZeroDuration.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - Test AudioParam.linearRampToValue - - - - - -
-
-
- - From 9034ec1b073745dfb8d9af4fce0dab199e1f0e0a Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:50:04 +0200 Subject: [PATCH 48/80] Bug 1308436 - Update other WPT expectations for event-insertion.html. r=karlt --HG-- extra : rebase_source : 62fe4d57809469e62d85761bda955ed7feb87b90 --- .../event-insertion.html.ini | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini index 73896a59e0d2..3164e8d3f47c 100644 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html.ini @@ -1,25 +1,10 @@ [event-insertion.html] - [X setValueCurveAtTime([98,99\], 0.0234375, 0.0078125) incorrectly threw TypeError: "Argument 1 of AudioParam.setValueCurveAtTime does not implement interface Float32Array.".] - expected: FAIL - - [X setValueCurveAtTime([3,4\], 0.0234375, 0.0078125) incorrectly threw TypeError: "Argument 1 of AudioParam.setValueCurveAtTime does not implement interface Float32Array.".] - expected: FAIL - - [X Output at frame 512 (time 0.03125) is not equal to 4. Got 3.] - expected: FAIL - - [< [Insert same event at same time\] 3 out of 12 assertions were failed.] - expected: FAIL - - [# AUDIT TASK RUNNER FINISHED: 1 out of 4 tasks were failed.] + [< [Insert same event at same time\] 1 out of 12 assertions were failed.] expected: FAIL [X Output at frame 384 (time 0.0234375) is not equal to 3. Got 98.] expected: FAIL - [X Output at frame 512 (time 0.03125) is not equal to 4. Got 99.] - expected: FAIL - - [< [Insert same event at same time\] 2 out of 12 assertions were failed.] + [# AUDIT TASK RUNNER FINISHED: 1 out of 4 tasks were failed.] expected: FAIL From f3e6802fb3dd0860309edea8864a3af00ba51ddf Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:50:26 +0200 Subject: [PATCH 49/80] Bug 1308436 - Update devtools tests with another Web Audio API call the throws the right exception. r=karlt --HG-- extra : rebase_source : fef09e298c9a9f64f7bc43b3db54e31b63732175 --- devtools/client/webaudioeditor/test/doc_bug_1112378.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/devtools/client/webaudioeditor/test/doc_bug_1112378.html b/devtools/client/webaudioeditor/test/doc_bug_1112378.html index 910a89f5145f..f96c4da76109 100644 --- a/devtools/client/webaudioeditor/test/doc_bug_1112378.html +++ b/devtools/client/webaudioeditor/test/doc_bug_1112378.html @@ -14,11 +14,11 @@ "use strict"; const ctx = new AudioContext(); - const osc = ctx.createOscillator(); + const panner = ctx.createStereoPanner(); function throwError() { try { - osc.connect({}); + panner.connect({}); } catch (e) { return { lineNumber: e.lineNumber, @@ -34,7 +34,7 @@ function throwDOMException() { try { - osc.frequency.setValueAtTime(0, -1); + panner.channelCount = 3; } catch (e) { return { lineNumber: e.lineNumber, From e21ce179fd5d228d1d4c6d31e5075e2d01f28ebd Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:51:27 +0200 Subject: [PATCH 50/80] Bug 1308436 - Remove audioparam-setValueCurve-exceptions.html.ini, it's now passing. r=karlt --HG-- extra : rebase_source : a24083282ac1bf52c31144700e1532467261b3ff --- ...dioparam-setValueCurve-exceptions.html.ini | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini deleted file mode 100644 index 29cf7a1a8fdc..000000000000 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html.ini +++ /dev/null @@ -1,46 +0,0 @@ -[audioparam-setValueCurve-exceptions.html] - [X setValueAtTime(1, 0.018750000000000003) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X linearRampToValueAtTime(1, 0.018750000000000003) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X exponentialRampToValueAtTime(1, 0.018750000000000003) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X setTargetAtTime(1, 0.018750000000000003, 1) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [< [setValueCurve\] 4 out of 6 assertions were failed.] - expected: FAIL - - [X setValueCurveAtTime(curve, 0.00625, 0.01) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X setValueCurveAtTime(curve, 0.018750000000000003, 0.01) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X setValueCurveAtTime(curve, 0.03125, 0.01) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X setValueCurveAtTime(curve, 0.043750000000000004, 0.01) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [X setValueCurveAtTime(curve, 0.031415926535897934, 0.01) threw "SyntaxError" instead of NotSupportedError.] - expected: FAIL - - [< [automations\] 5 out of 13 assertions were failed.] - expected: FAIL - - [X setValueCurveAtTime([\], 0, 0.01) threw "SyntaxError" instead of InvalidStateError.] - expected: FAIL - - [X setValueCurveAtTime([1\], 0, 0.01) did not throw an exception.] - expected: FAIL - - [< [curve lengths\] 2 out of 3 assertions were failed.] - expected: FAIL - - [# AUDIT TASK RUNNER FINISHED: 3 out of 5 tasks were failed.] - expected: FAIL - From 0bafea4ccb3d1b7d56536f28d19a919cee3e5b99 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:56:23 +0200 Subject: [PATCH 51/80] Bug 1308436 - Remove expectation file for audioparam-exceptional-values.html.ini, it now passes. r=karlt --HG-- extra : rebase_source : acdddbc8986ecf9681bb0af51fbe612ec0081b16 --- .../audioparam-exceptional-values.html.ini | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini deleted file mode 100644 index 094a59dd09db..000000000000 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html.ini +++ /dev/null @@ -1,70 +0,0 @@ -[audioparam-exceptional-values.html] - [X gain.gain.setValueAtTime(1,-1) threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X gain.gain.linearRampToValueAtTime(1,-1) threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(1,-1) threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X gain.gain.setTargetAtTime(1,-1,1) threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X gain.gain.setTargetAtTime(1,1,-1) threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X gain.gain.setValueCurveAtTime([0,0,0\],-1,1) threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X gain.gain.setValueCurveAtTime([0,0,0\],1,-1) did not throw an exception.] - expected: FAIL - - [X gain.gain.setValueCurveAtTime(curve, 1, 0) did not throw an exception.] - expected: FAIL - - [< [special cases 1\] 8 out of 8 assertions were failed.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(0,1) threw "SyntaxError" instead of RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(-1e-100,1) threw "SyntaxError" instead of RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(1e-100,1) threw "SyntaxError" instead of RangeError.] - expected: FAIL - - [< [special cases 2\] 3 out of 3 assertions were failed.] - expected: FAIL - - [# AUDIT TASK RUNNER FINISHED: 2 out of 6 tasks were failed.] - expected: FAIL - - [X gain.gain.setTargetAtTime(1,-1,1) threw "NotSupportedError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(-1e-100,1) threw "SyntaxError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.linearRampToValueAtTime(1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(0,1) threw "SyntaxError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.setValueCurveAtTime([0,0,0\],-1,1) threw "NotSupportedError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.setValueAtTime(1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(1e-100,1) threw "SyntaxError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.exponentialRampToValueAtTime(1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] - expected: FAIL - - [X gain.gain.setTargetAtTime(1,1,-1) threw "NotSupportedError" instead of EcmaScript error RangeError.] - expected: FAIL - From f1e68904573c720c4aca658c4a692f119ce3e6ce Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:56:50 +0200 Subject: [PATCH 52/80] Bug 1308436 - Fix a test case and add more test cases for overlapping SetValueCurveAtTime. r=karlt --HG-- extra : rebase_source : eb5afbe8618242c29cc9057c49bb17de0aaeee15 --- testing/web-platform/meta/MANIFEST.json | 4 +- .../audioparam-setValueCurve-exceptions.html | 71 +++++++++++++++++++ .../event-insertion.html | 6 +- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 83b6a77cfcd8..20935804299d 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -650293,7 +650293,7 @@ "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html": [ - "a7182dba59b8c3d21b1a6b4dd7ac2d3bf997ab33", + "7990d0aee134cb33082e058b41bdaafc69bb507e", "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html": [ @@ -650313,7 +650313,7 @@ "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/event-insertion.html": [ - "eab77c494d1161083f1fe73376492b177355995f", + "688d0478235e202859c7939eef65ad383f7a4f36", "testharness" ], "webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet.https.html": [ diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html index a7182dba59b8..7990d0aee134 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html @@ -286,6 +286,77 @@ task.done(); }); + audit.define('curve overlap', (task, should) => { + let context = + new OfflineAudioContext(1, testDurationFrames, sampleRate); + let g = context.createGain(); + let startTime = 5; + let startTimeLater = 10; + let startTimeEarlier = 2.5; + let curveDuration = 10; + let curveDurationShorter = 5; + let curve = [1, 2, 3]; + + // Having an event that ends at time t and then starting a ramp at time + // t should work. + should( + () => { + g.gain.linearRampToValueAtTime(1.0, startTime); + }, + `g.gain.linearRampToValueAtTime(1.0, ${startTime})`) + .notThrow(); + + // An initial curve event, starting from the end of the linear ramp. + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime, curveDuration); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`) + .notThrow(); + + // Check that an exception is thrown when trying to overlap two curves, + // in various ways + + // Same start time and end time (curve exactly overlapping) + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime, curveDuration); + }, + `second g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDuration})`) + .throw('NotSupportedError'); + // Same start time, shorter end time + should( + () => { + g.gain.setValueCurveAtTime(curve, startTime, curveDurationShorter); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTime}, ${curveDurationShorter})`) + .throw('NotSupportedError'); + // Earlier start time, end time after the start time of an another curve + should( + () => { + g.gain.setValueCurveAtTime(curve, startTimeEarlier, curveDuration); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTimeEarlier}, ${curveDuration})`) + .throw('NotSupportedError'); + // Start time after the start time of the other curve, but earlier than + // its end. + should( + () => { + g.gain.setValueCurveAtTime(curve, startTimeLater, curveDuration); + }, + `g.gain.setValueCurveAtTime([${curve}], ${startTimeLater}, ${curveDuration})`) + .throw('NotSupportedError'); + // Setting an event exactly at the end of the curve should work. + should( + () => { + g.gain.setValueAtTime(1.0, startTime + curveDuration); + }, + `g.gain.setValueAtTime(1.0, ${startTime + curveDuration})`) + .notThrow(); + + task.done(); + }); + audit.define('curve lengths', (task, should) => { let context = new OfflineAudioContext(1, testDurationFrames, sampleRate); diff --git a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html index eab77c494d11..688d0478235e 100644 --- a/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html +++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audioparam-interface/event-insertion.html @@ -30,8 +30,8 @@ // An array of tests to be done. Each entry specifies the event // type and the event time. The events are inserted in the order - // given (in |values|), and the second event should replace the - // first, as required by the spec. + // given (in |values|), and the second event should be inserted + // after the first one, as required by the spec. let testCases = [ { event: 'setValueAtTime', @@ -57,7 +57,7 @@ { event: 'setValueCurveAtTime', frame: 3 * RENDER_QUANTUM_FRAMES, - values: [[98, 99], [3, 4]], + values: [[3, 4]], extraArgs: RENDER_QUANTUM_FRAMES / context.sampleRate, outputTestFrame: 4 * RENDER_QUANTUM_FRAMES, expectedOutputValue: 4 From 35f174a2b4d455a203bd45bd9fbf2c04164bf7b9 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 14:57:25 +0200 Subject: [PATCH 53/80] Bug 1308436 - Remove test_audioParamSetCurveAtTimeTwice.html because it's now wrong per spec. r=karlt --HG-- extra : rebase_source : 9327fbfa9ec655fcf222145aa07803db9b583a17 --- dom/media/webaudio/test/mochitest.ini | 1 - .../test_audioParamSetCurveAtTimeTwice.html | 68 ------------------- 2 files changed, 69 deletions(-) delete mode 100644 dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html diff --git a/dom/media/webaudio/test/mochitest.ini b/dom/media/webaudio/test/mochitest.ini index 105105a94dd9..a840aa06bfe4 100644 --- a/dom/media/webaudio/test/mochitest.ini +++ b/dom/media/webaudio/test/mochitest.ini @@ -73,7 +73,6 @@ tags=capturestream [test_audioParamGain.html] [test_audioParamLinearRamp.html] [test_audioParamSetCurveAtTime.html] -[test_audioParamSetCurveAtTimeTwice.html] [test_audioParamSetTargetAtTime.html] [test_audioParamSetTargetAtTimeZeroTimeConstant.html] [test_audioParamSetValueAtTime.html] diff --git a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html b/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html deleted file mode 100644 index 0f976380e077..000000000000 --- a/dom/media/webaudio/test/test_audioParamSetCurveAtTimeTwice.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - Test AudioParam.setValueCurveAtTime twice - - - - - -
-
-
- - From f9f9df7b5e006d0796cf5eab4cc78ca0fced8785 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 15:27:28 +0200 Subject: [PATCH 54/80] Bug 1308436 - Update WPT expectations for audioparam-method-chaining.html. r=karlt --HG-- extra : rebase_source : c4cd89d2c9ad6ab17d5ce7d26b0ab8e1b351945c --- .../audioparam-method-chaining.html.ini | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini index 45f6de7bb97d..8fd28847a7ed 100644 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html.ini @@ -1,14 +1,8 @@ [audioparam-method-chaining.html] - [X Calling setValueAtTime() with a negative end time threw "NotSupportedError" instead of RangeError.] - expected: FAIL - - [X Calling exponentialRampToValueAtTime() with a zero target value threw "SyntaxError" instead of RangeError.] - expected: FAIL - [X The gain value of the second gain node is not equal to 0.5. Got 1.] expected: FAIL - [< [invalid-operation\] 3 out of 4 assertions were failed.] + [< [invalid-operation\] 1 out of 4 assertions were failed.] expected: FAIL [# AUDIT TASK RUNNER FINISHED: 1 out of 3 tasks were failed.] From 7953a4769c84b1dde84b4e3a5bcf90cb1c992116 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 4 Sep 2018 17:05:41 +0200 Subject: [PATCH 55/80] Bug 1488218 - Remove one more unneeded keyword in dom/media/webaudio. r=karlt Differential Revision: https://phabricator.services.mozilla.com/D4866 --HG-- extra : rebase_source : 8790e201432d6f2030ef0f4ff4eee24054ce09ec --- dom/media/webaudio/AudioParamTimeline.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/webaudio/AudioParamTimeline.h b/dom/media/webaudio/AudioParamTimeline.h index 84ab2403bcfc..46f2462c314f 100644 --- a/dom/media/webaudio/AudioParamTimeline.h +++ b/dom/media/webaudio/AudioParamTimeline.h @@ -53,7 +53,7 @@ public: void InsertEvent(const AudioTimelineEvent& aEvent) { if (aEvent.mType == AudioTimelineEvent::Cancel) { - CancelScheduledValues(aEvent.template Time()); + CancelScheduledValues(aEvent.Time()); return; } if (aEvent.mType == AudioTimelineEvent::Stream) { From 7dd4c36d7ae492cf43d3cf46be515cd6d6df2fb7 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Tue, 4 Sep 2018 18:39:24 +0300 Subject: [PATCH 56/80] Bug 1487273 - add a limit how often forget skippable only cycles run, r=mccr8 --HG-- extra : rebase_source : e0c051d0af828c0febd99e6866f2770eccdce89a --- dom/base/nsJSEnvironment.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 4e43985a56af..b2bdbc2d5dfa 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -120,6 +120,11 @@ const size_t gStackSize = 8192; #define NS_CC_SKIPPABLE_DELAY 250 // ms +// In case the cycle collector isn't run at all, we don't want +// forget skippables to run too often. So limit the forget skippable cycle to +// start at earliest 2000 ms after the end of the previous cycle. +#define NS_TIME_BETWEEN_FORGET_SKIPPABLE_CYCLES 2000 // ms + // ForgetSkippable is usually fast, so we can use small budgets. // This isn't a real budget but a hint to IdleTaskRunner whether there // is enough time to call ForgetSkippable. @@ -161,6 +166,8 @@ static StaticRefPtr sInterSliceGCRunner; static TimeStamp sLastCCEndTime; +static TimeStamp sLastForgetSkippableCycleEndTime; + static bool sCCLockedOut; static PRTime sCCLockedOutTime; @@ -2014,6 +2021,10 @@ CCRunnerFired(TimeStamp aDeadline) // next time, so kill the timer. sPreviousSuspectedCount = 0; nsJSContext::KillCCRunner(); + + if (!didDoWork) { + sLastForgetSkippableCycleEndTime = TimeStamp::Now(); + } } return didDoWork; @@ -2228,6 +2239,17 @@ nsJSContext::MaybePokeCC() return; } + // If GC hasn't run recently and forget skippable only cycle was run, + // don't start a new cycle too soon. + if (sCleanupsSinceLastGC > NS_MAJOR_FORGET_SKIPPABLE_CALLS) { + uint32_t sinceLastForgetSkippableCycle = + TimeUntilNow(sLastForgetSkippableCycleEndTime); + if (sinceLastForgetSkippableCycle && + sinceLastForgetSkippableCycle < NS_TIME_BETWEEN_FORGET_SKIPPABLE_CYCLES) { + return; + } + } + if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { sCCRunnerFireCount = 0; @@ -2490,6 +2512,7 @@ mozilla::dom::StartupJSEnvironment() sCCLockedOut = false; sCCLockedOutTime = 0; sLastCCEndTime = TimeStamp(); + sLastForgetSkippableCycleEndTime = TimeStamp(); sHasRunGC = false; sPendingLoadCount = 0; sLoadingInProgress = false; From 02dbdb12a96a981f2048521a30d871c74e5fd048 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Tue, 4 Sep 2018 19:24:12 +0300 Subject: [PATCH 57/80] Backed out changeset 7ffb06278c4c (bug 1488114) for xpcshell failures on test_change_pixel_ratio.js. CLOSED TREE --- .../locales/en-US/responsive.properties | 7 +++-- .../client/responsive.html/actions/devices.js | 3 +- .../actions/display-pixel-ratio.js | 23 ++++++++++++++ .../client/responsive.html/actions/index.js | 12 +++---- .../responsive.html/actions/location.js | 22 +++++++++++++ .../client/responsive.html/actions/moz.build | 3 ++ .../actions/reload-conditions.js | 3 +- .../responsive.html/actions/screenshot.js | 3 +- .../actions/touch-simulation.js | 22 +++++++++++++ devtools/client/responsive.html/actions/ui.js | 21 ------------- .../client/responsive.html/browser/swap.js | 2 +- .../responsive.html/browser/web-navigation.js | 1 - .../client/responsive.html/components/App.js | 22 +++++++------ .../components/DevicePixelRatioMenu.js | 10 +++--- .../components/ResizableViewport.js | 4 +-- .../responsive.html/components/Toolbar.js | 16 +++++----- .../components/ViewportDimension.js | 4 +-- .../responsive.html/components/Viewports.js | 6 ++-- devtools/client/responsive.html/index.js | 4 ++- devtools/client/responsive.html/manager.js | 5 +-- devtools/client/responsive.html/reducers.js | 3 ++ .../responsive.html/reducers/devices.js | 6 ++-- .../reducers/display-pixel-ratio.js | 26 ++++++++++++++++ .../responsive.html/reducers/location.js | 25 +++++++++++++++ .../client/responsive.html/reducers/moz.build | 3 ++ .../responsive.html/reducers/screenshot.js | 4 +-- .../reducers/touch-simulation.js | 31 +++++++++++++++++++ .../client/responsive.html/reducers/ui.js | 18 ----------- .../responsive.html/reducers/viewports.js | 8 +++-- .../unit/test_change_display_pixel_ratio.js | 4 +-- .../test/unit/test_change_location.js | 22 +++++++++++++ .../test_update_touch_simulation_enabled.js | 6 ++-- .../responsive.html/test/unit/xpcshell.ini | 1 + devtools/client/responsive.html/types.js | 17 +++++++++- 34 files changed, 265 insertions(+), 102 deletions(-) create mode 100644 devtools/client/responsive.html/actions/display-pixel-ratio.js create mode 100644 devtools/client/responsive.html/actions/location.js create mode 100644 devtools/client/responsive.html/actions/touch-simulation.js create mode 100644 devtools/client/responsive.html/reducers/display-pixel-ratio.js create mode 100644 devtools/client/responsive.html/reducers/location.js create mode 100644 devtools/client/responsive.html/reducers/touch-simulation.js create mode 100644 devtools/client/responsive.html/test/unit/test_change_location.js diff --git a/devtools/client/locales/en-US/responsive.properties b/devtools/client/locales/en-US/responsive.properties index aaa9c524a8d1..6e2ede4ee46c 100644 --- a/devtools/client/locales/en-US/responsive.properties +++ b/devtools/client/locales/en-US/responsive.properties @@ -124,9 +124,10 @@ responsive.reloadConditions.touchSimulation=Reload when touch simulation is togg # to select whether to reload when user agent is changed. responsive.reloadConditions.userAgent=Reload when user agent is changed -# LOCALIZATION NOTE (responsive.reloadNotification.description2): Text in notification bar -# shown on first open to clarify that some features need a reload to apply. -responsive.reloadNotification.description2=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the Settings menu. +# LOCALIZATION NOTE (responsive.reloadNotification.description): Text in notification bar +# shown on first open to clarify that some features need a reload to apply. %1$S is the +# label on the reload conditions menu (responsive.reloadConditions.label). +responsive.reloadNotification.description=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the “%1$S” menu. # LOCALIZATION NOTE (responsive.leftAlignViewport): Label on checkbox used in the settings # menu. diff --git a/devtools/client/responsive.html/actions/devices.js b/devtools/client/responsive.html/actions/devices.js index 0726596d95eb..13a8fc4ccb05 100644 --- a/devtools/client/responsive.html/actions/devices.js +++ b/devtools/client/responsive.html/actions/devices.js @@ -4,8 +4,6 @@ "use strict"; -const Services = require("Services"); - const { ADD_DEVICE, ADD_DEVICE_TYPE, @@ -20,6 +18,7 @@ const { removeDeviceAssociation } = require("./viewports"); const { addDevice, getDevices, removeDevice } = require("devtools/client/shared/devices"); +const Services = require("Services"); const DISPLAYED_DEVICES_PREF = "devtools.responsive.html.displayedDeviceList"; /** diff --git a/devtools/client/responsive.html/actions/display-pixel-ratio.js b/devtools/client/responsive.html/actions/display-pixel-ratio.js new file mode 100644 index 000000000000..ff3343bb5d02 --- /dev/null +++ b/devtools/client/responsive.html/actions/display-pixel-ratio.js @@ -0,0 +1,23 @@ +/* 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 { CHANGE_DISPLAY_PIXEL_RATIO } = require("./index"); + +module.exports = { + + /** + * The pixel ratio of the display has changed. This may be triggered by the user + * when changing the monitor resolution, or when the window is dragged to a different + * display with a different pixel ratio. + */ + changeDisplayPixelRatio(displayPixelRatio) { + return { + type: CHANGE_DISPLAY_PIXEL_RATIO, + displayPixelRatio, + }; + }, + +}; diff --git a/devtools/client/responsive.html/actions/index.js b/devtools/client/responsive.html/actions/index.js index 5306161dd6f1..0db4d70e1254 100644 --- a/devtools/client/responsive.html/actions/index.js +++ b/devtools/client/responsive.html/actions/index.js @@ -4,9 +4,9 @@ "use strict"; -// This file lists all of the actions available in responsive design. This +// This file lists all of the actions available in responsive design. This // central list of constants makes it easy to see all possible action names at -// a glance. Please add a comment with each new action type. +// a glance. Please add a comment with each new action type. const { createEnum } = require("devtools/client/shared/enum"); @@ -28,7 +28,7 @@ createEnum([ // Change the device displayed in the viewport. "CHANGE_DEVICE", - // Change the location of the page. This may be triggered by the user + // Change the location of the page. This may be triggered by the user // directly entering a new URL, navigating with links, etc. "CHANGE_LOCATION", @@ -48,6 +48,9 @@ createEnum([ // Change one of the reload conditions. "CHANGE_RELOAD_CONDITION", + // Change the touch simulation state. + "CHANGE_TOUCH_SIMULATION", + // Indicates that the device list is being loaded. "LOAD_DEVICE_LIST_START", @@ -81,9 +84,6 @@ createEnum([ // Toggles the left alignment of the viewports. "TOGGLE_LEFT_ALIGNMENT", - // Toggles the touch simulation state of the viewports. - "TOGGLE_TOUCH_SIMULATION", - // Update the device display state in the device selector. "UPDATE_DEVICE_DISPLAYED", diff --git a/devtools/client/responsive.html/actions/location.js b/devtools/client/responsive.html/actions/location.js new file mode 100644 index 000000000000..565825e5e655 --- /dev/null +++ b/devtools/client/responsive.html/actions/location.js @@ -0,0 +1,22 @@ +/* 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 { CHANGE_LOCATION } = require("./index"); + +module.exports = { + + /** + * The location of the page has changed. This may be triggered by the user + * directly entering a new URL, navigating with links, etc. + */ + changeLocation(location) { + return { + type: CHANGE_LOCATION, + location, + }; + }, + +}; diff --git a/devtools/client/responsive.html/actions/moz.build b/devtools/client/responsive.html/actions/moz.build index ae665ef2348b..26e34ff8b0da 100644 --- a/devtools/client/responsive.html/actions/moz.build +++ b/devtools/client/responsive.html/actions/moz.build @@ -6,9 +6,12 @@ DevToolsModules( 'devices.js', + 'display-pixel-ratio.js', 'index.js', + 'location.js', 'reload-conditions.js', 'screenshot.js', + 'touch-simulation.js', 'ui.js', 'viewports.js', ) diff --git a/devtools/client/responsive.html/actions/reload-conditions.js b/devtools/client/responsive.html/actions/reload-conditions.js index 22485a14e98f..732f8a738166 100644 --- a/devtools/client/responsive.html/actions/reload-conditions.js +++ b/devtools/client/responsive.html/actions/reload-conditions.js @@ -4,14 +4,13 @@ "use strict"; -const Services = require("Services"); - const { CHANGE_RELOAD_CONDITION, LOAD_RELOAD_CONDITIONS_END, } = require("./index"); const Types = require("../types"); +const Services = require("Services"); const PREF_PREFIX = "devtools.responsive.reloadConditions."; diff --git a/devtools/client/responsive.html/actions/screenshot.js b/devtools/client/responsive.html/actions/screenshot.js index 317ae23e00a1..482eff85b8c1 100644 --- a/devtools/client/responsive.html/actions/screenshot.js +++ b/devtools/client/responsive.html/actions/screenshot.js @@ -6,8 +6,6 @@ "use strict"; -const Services = require("Services"); - const { TAKE_SCREENSHOT_START, TAKE_SCREENSHOT_END, @@ -16,6 +14,7 @@ const { const { getFormatStr } = require("../utils/l10n"); const { getTopLevelWindow } = require("../utils/window"); const e10s = require("../utils/e10s"); +const Services = require("Services"); const CAMERA_AUDIO_URL = "resource://devtools/client/themes/audio/shutter.wav"; diff --git a/devtools/client/responsive.html/actions/touch-simulation.js b/devtools/client/responsive.html/actions/touch-simulation.js new file mode 100644 index 000000000000..8f98101e7a78 --- /dev/null +++ b/devtools/client/responsive.html/actions/touch-simulation.js @@ -0,0 +1,22 @@ +/* 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/. */ + +/* eslint-env browser */ + +"use strict"; + +const { + CHANGE_TOUCH_SIMULATION +} = require("./index"); + +module.exports = { + + changeTouchSimulation(enabled) { + return { + type: CHANGE_TOUCH_SIMULATION, + enabled, + }; + }, + +}; diff --git a/devtools/client/responsive.html/actions/ui.js b/devtools/client/responsive.html/actions/ui.js index 95abe2bf3c1b..22399f294290 100644 --- a/devtools/client/responsive.html/actions/ui.js +++ b/devtools/client/responsive.html/actions/ui.js @@ -5,25 +5,11 @@ "use strict"; const { - CHANGE_DISPLAY_PIXEL_RATIO, TOGGLE_LEFT_ALIGNMENT, - TOGGLE_TOUCH_SIMULATION, } = require("./index"); module.exports = { - /** - * The pixel ratio of the display has changed. This may be triggered by the user - * when changing the monitor resolution, or when the window is dragged to a different - * display with a different pixel ratio. - */ - changeDisplayPixelRatio(displayPixelRatio) { - return { - type: CHANGE_DISPLAY_PIXEL_RATIO, - displayPixelRatio, - }; - }, - toggleLeftAlignment(enabled) { return { type: TOGGLE_LEFT_ALIGNMENT, @@ -31,11 +17,4 @@ module.exports = { }; }, - toggleTouchSimulation(enabled) { - return { - type: TOGGLE_TOUCH_SIMULATION, - enabled, - }; - }, - }; diff --git a/devtools/client/responsive.html/browser/swap.js b/devtools/client/responsive.html/browser/swap.js index b3d79701110f..3287ce743426 100644 --- a/devtools/client/responsive.html/browser/swap.js +++ b/devtools/client/responsive.html/browser/swap.js @@ -5,9 +5,9 @@ "use strict"; const { Ci } = require("chrome"); -const Services = require("Services"); const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm"); const { tunnelToInnerBrowser } = require("./tunnel"); +const Services = require("Services"); function debug(msg) { // console.log(`RDM swap: ${msg}`); diff --git a/devtools/client/responsive.html/browser/web-navigation.js b/devtools/client/responsive.html/browser/web-navigation.js index c82973201d09..f28f26ce9b6b 100644 --- a/devtools/client/responsive.html/browser/web-navigation.js +++ b/devtools/client/responsive.html/browser/web-navigation.js @@ -10,7 +10,6 @@ const Services = require("Services"); const { NetUtil } = require("resource://gre/modules/NetUtil.jsm"); const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm"); const Telemetry = require("devtools/client/shared/telemetry"); - const telemetry = new Telemetry(); function readInputStreamToString(stream) { diff --git a/devtools/client/responsive.html/components/App.js b/devtools/client/responsive.html/components/App.js index d4413a8f8f2d..e25a26fbef61 100644 --- a/devtools/client/responsive.html/components/App.js +++ b/devtools/client/responsive.html/components/App.js @@ -6,7 +6,7 @@ "use strict"; -const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); +const { Component, createFactory } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect } = require("devtools/client/shared/vendor/react-redux"); @@ -27,10 +27,8 @@ const { } = require("../actions/devices"); const { changeReloadCondition } = require("../actions/reload-conditions"); const { takeScreenshot } = require("../actions/screenshot"); -const { - toggleTouchSimulation, - toggleLeftAlignment, -} = require("../actions/ui"); +const { changeTouchSimulation } = require("../actions/touch-simulation"); +const { toggleLeftAlignment } = require("../actions/ui"); const { changeDevice, changePixelRatio, @@ -41,14 +39,16 @@ const { const Types = require("../types"); -class App extends PureComponent { +class App extends Component { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, dispatch: PropTypes.func.isRequired, + displayPixelRatio: Types.pixelRatio.value.isRequired, networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired, reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired, screenshot: PropTypes.shape(Types.screenshot).isRequired, + touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired, viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired, }; } @@ -93,7 +93,7 @@ class App extends PureComponent { device, }, "*"); this.props.dispatch(changeDevice(id, device.name, deviceType)); - this.props.dispatch(toggleTouchSimulation(device.touch)); + this.props.dispatch(changeTouchSimulation(device.touch)); this.props.dispatch(changePixelRatio(id, device.pixelRatio)); } @@ -123,7 +123,7 @@ class App extends PureComponent { type: "change-touch-simulation", enabled, }, "*"); - this.props.dispatch(toggleTouchSimulation(enabled)); + this.props.dispatch(changeTouchSimulation(enabled)); } onContentResize({ width, height }) { @@ -150,7 +150,7 @@ class App extends PureComponent { // TODO: Bug 1332754: Move messaging and logic into the action creator so that device // property changes are sent from there instead of this function. this.props.dispatch(removeDeviceAssociation(id)); - this.props.dispatch(toggleTouchSimulation(false)); + this.props.dispatch(changeTouchSimulation(false)); this.props.dispatch(changePixelRatio(id, 0)); } @@ -181,9 +181,11 @@ class App extends PureComponent { render() { const { devices, + displayPixelRatio, networkThrottling, reloadConditions, screenshot, + touchSimulation, viewports, } = this.props; @@ -224,11 +226,13 @@ class App extends PureComponent { dom.div({ id: "app" }, Toolbar({ devices, + displayPixelRatio, networkThrottling, reloadConditions, screenshot, selectedDevice, selectedPixelRatio, + touchSimulation, viewport: viewports[0], onChangeDevice, onChangeNetworkThrottling, diff --git a/devtools/client/responsive.html/components/DevicePixelRatioMenu.js b/devtools/client/responsive.html/components/DevicePixelRatioMenu.js index 473e6c65d235..75fa97d553e5 100644 --- a/devtools/client/responsive.html/components/DevicePixelRatioMenu.js +++ b/devtools/client/responsive.html/components/DevicePixelRatioMenu.js @@ -21,10 +21,10 @@ class DevicePixelRatioMenu extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, - displayPixelRatio: PropTypes.number.isRequired, + displayPixelRatio: Types.pixelRatio.value.isRequired, onChangePixelRatio: PropTypes.func.isRequired, selectedDevice: PropTypes.string.isRequired, - selectedPixelRatio: PropTypes.number.isRequired, + selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired, }; } @@ -44,8 +44,8 @@ class DevicePixelRatioMenu extends PureComponent { return { label: getFormatStr("responsive.devicePixelRatioOption", value), type: "checkbox", - checked: selectedPixelRatio > 0 ? - selectedPixelRatio === value : + checked: selectedPixelRatio.value > 0 ? + selectedPixelRatio.value === value : displayPixelRatio === value, click: () => onChangePixelRatio(+value), }; @@ -86,7 +86,7 @@ class DevicePixelRatioMenu extends PureComponent { }, dom.span({ className: "title" }, getFormatStr("responsive.devicePixelRatioOption", - selectedPixelRatio || displayPixelRatio) + selectedPixelRatio.value || displayPixelRatio) ) ) ); diff --git a/devtools/client/responsive.html/components/ResizableViewport.js b/devtools/client/responsive.html/components/ResizableViewport.js index 22120938990c..eefcf5c72206 100644 --- a/devtools/client/responsive.html/components/ResizableViewport.js +++ b/devtools/client/responsive.html/components/ResizableViewport.js @@ -6,7 +6,7 @@ "use strict"; -const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); +const { Component, createFactory } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); @@ -18,7 +18,7 @@ const Types = require("../types"); const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION; const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION; -class ResizableViewport extends PureComponent { +class ResizableViewport extends Component { static get propTypes() { return { leftAlignmentEnabled: PropTypes.bool.isRequired, diff --git a/devtools/client/responsive.html/components/Toolbar.js b/devtools/client/responsive.html/components/Toolbar.js index ce50e0cec769..b50162302872 100644 --- a/devtools/client/responsive.html/components/Toolbar.js +++ b/devtools/client/responsive.html/components/Toolbar.js @@ -22,7 +22,7 @@ class Toolbar extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, - displayPixelRatio: PropTypes.number.isRequired, + displayPixelRatio: Types.pixelRatio.value.isRequired, leftAlignmentEnabled: PropTypes.bool.isRequired, networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired, onChangeDevice: PropTypes.func.isRequired, @@ -40,8 +40,8 @@ class Toolbar extends PureComponent { reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired, screenshot: PropTypes.shape(Types.screenshot).isRequired, selectedDevice: PropTypes.string.isRequired, - selectedPixelRatio: PropTypes.number.isRequired, - touchSimulationEnabled: PropTypes.bool.isRequired, + selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired, + touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired, viewport: PropTypes.shape(Types.viewport).isRequired, }; } @@ -68,7 +68,7 @@ class Toolbar extends PureComponent { screenshot, selectedDevice, selectedPixelRatio, - touchSimulationEnabled, + touchSimulation, viewport, } = this.props; @@ -121,10 +121,10 @@ class Toolbar extends PureComponent { dom.button({ id: "touch-simulation-button", className: "devtools-button" + - (touchSimulationEnabled ? " checked" : ""), - title: (touchSimulationEnabled ? + (touchSimulation.enabled ? " checked" : ""), + title: (touchSimulation.enabled ? getStr("responsive.disableTouch") : getStr("responsive.enableTouch")), - onClick: () => onChangeTouchSimulation(!touchSimulationEnabled), + onClick: () => onChangeTouchSimulation(!touchSimulation.enabled), }) ), dom.div( @@ -156,9 +156,7 @@ class Toolbar extends PureComponent { const mapStateToProps = state => { return { - displayPixelRatio: state.ui.displayPixelRatio, leftAlignmentEnabled: state.ui.leftAlignmentEnabled, - touchSimulationEnabled: state.ui.touchSimulationEnabled, }; }; diff --git a/devtools/client/responsive.html/components/ViewportDimension.js b/devtools/client/responsive.html/components/ViewportDimension.js index f21576bbd363..6283427f82ac 100644 --- a/devtools/client/responsive.html/components/ViewportDimension.js +++ b/devtools/client/responsive.html/components/ViewportDimension.js @@ -4,7 +4,7 @@ "use strict"; -const { PureComponent } = require("devtools/client/shared/vendor/react"); +const { Component } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); @@ -12,7 +12,7 @@ const { isKeyIn } = require("../utils/key"); const { MIN_VIEWPORT_DIMENSION } = require("../constants"); const Types = require("../types"); -class ViewportDimension extends PureComponent { +class ViewportDimension extends Component { static get propTypes() { return { onResizeViewport: PropTypes.func.isRequired, diff --git a/devtools/client/responsive.html/components/Viewports.js b/devtools/client/responsive.html/components/Viewports.js index dcdb3bb0ae6e..18aca2230417 100644 --- a/devtools/client/responsive.html/components/Viewports.js +++ b/devtools/client/responsive.html/components/Viewports.js @@ -4,16 +4,16 @@ "use strict"; -const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); +const { Component, createFactory } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); -const { connect } = require("devtools/client/shared/vendor/react-redux"); const ResizableViewport = createFactory(require("./ResizableViewport")); const Types = require("../types"); -class Viewports extends PureComponent { +class Viewports extends Component { static get propTypes() { return { leftAlignmentEnabled: PropTypes.bool.isRequired, diff --git a/devtools/client/responsive.html/index.js b/devtools/client/responsive.html/index.js index 7248f8b7638b..a4207182b17c 100644 --- a/devtools/client/responsive.html/index.js +++ b/devtools/client/responsive.html/index.js @@ -23,9 +23,10 @@ const message = require("./utils/message"); const App = createFactory(require("./components/App")); const Store = require("./store"); const { loadDevices } = require("./actions/devices"); +const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio"); +const { changeLocation } = require("./actions/location"); const { loadReloadConditions } = require("./actions/reload-conditions"); const { addViewport, resizeViewport } = require("./actions/viewports"); -const { changeDisplayPixelRatio } = require("./actions/ui"); // Exposed for use by tests window.require = require; @@ -116,6 +117,7 @@ function onDevicePixelRatioChange() { window.addInitialViewport = ({ uri, userContextId }) => { try { onDevicePixelRatioChange(); + bootstrap.dispatch(changeLocation(uri)); bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio)); bootstrap.dispatch(addViewport(userContextId)); } catch (e) { diff --git a/devtools/client/responsive.html/manager.js b/devtools/client/responsive.html/manager.js index df5d6f5909e9..931a619f64df 100644 --- a/devtools/client/responsive.html/manager.js +++ b/devtools/client/responsive.html/manager.js @@ -491,7 +491,8 @@ ResponsiveUI.prototype = { showReloadNotification() { if (Services.prefs.getBoolPref(RELOAD_NOTIFICATION_PREF, false)) { showNotification(this.browserWindow, this.tab, { - msg: l10n.getFormatStr("responsive.reloadNotification.description2"), + msg: l10n.getFormatStr("responsive.reloadNotification.description", + l10n.getStr("responsive.reloadConditions.label")), }); Services.prefs.setBoolPref(RELOAD_NOTIFICATION_PREF, false); } @@ -580,7 +581,7 @@ ResponsiveUI.prototype = { async onChangeTouchSimulation(event) { const { enabled } = event.data; const reloadNeeded = await this.updateTouchSimulation(enabled) && - this.reloadOnChange("touchSimulation"); + this.reloadOnChange("touchSimulation"); if (reloadNeeded) { this.getViewportBrowser().reload(); } diff --git a/devtools/client/responsive.html/reducers.js b/devtools/client/responsive.html/reducers.js index e8fe16089eeb..f4f36d11db1d 100644 --- a/devtools/client/responsive.html/reducers.js +++ b/devtools/client/responsive.html/reducers.js @@ -5,8 +5,11 @@ "use strict"; exports.devices = require("./reducers/devices"); +exports.displayPixelRatio = require("./reducers/display-pixel-ratio"); +exports.location = require("./reducers/location"); exports.networkThrottling = require("devtools/client/shared/components/throttling/reducer"); exports.reloadConditions = require("./reducers/reload-conditions"); exports.screenshot = require("./reducers/screenshot"); +exports.touchSimulation = require("./reducers/touch-simulation"); exports.ui = require("./reducers/ui"); exports.viewports = require("./reducers/viewports"); diff --git a/devtools/client/responsive.html/reducers/devices.js b/devtools/client/responsive.html/reducers/devices.js index 45544e8cfae4..d42251d3bdb6 100644 --- a/devtools/client/responsive.html/reducers/devices.js +++ b/devtools/client/responsive.html/reducers/devices.js @@ -18,10 +18,10 @@ const { const Types = require("../types"); const INITIAL_DEVICES = { - isModalOpen: false, - listState: Types.loadableState.INITIALIZED, - modalOpenedFromViewport: null, types: [], + isModalOpen: false, + modalOpenedFromViewport: null, + listState: Types.loadableState.INITIALIZED, }; const reducers = { diff --git a/devtools/client/responsive.html/reducers/display-pixel-ratio.js b/devtools/client/responsive.html/reducers/display-pixel-ratio.js new file mode 100644 index 000000000000..dd1a9ae715d0 --- /dev/null +++ b/devtools/client/responsive.html/reducers/display-pixel-ratio.js @@ -0,0 +1,26 @@ +/* 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/. */ + +/* eslint-env browser */ + +"use strict"; + +const { CHANGE_DISPLAY_PIXEL_RATIO } = require("../actions/index"); +const INITIAL_DISPLAY_PIXEL_RATIO = 0; + +const reducers = { + + [CHANGE_DISPLAY_PIXEL_RATIO](_, action) { + return action.displayPixelRatio; + }, + +}; + +module.exports = function(displayPixelRatio = INITIAL_DISPLAY_PIXEL_RATIO, action) { + const reducer = reducers[action.type]; + if (!reducer) { + return displayPixelRatio; + } + return reducer(displayPixelRatio, action); +}; diff --git a/devtools/client/responsive.html/reducers/location.js b/devtools/client/responsive.html/reducers/location.js new file mode 100644 index 000000000000..02ccfdf08d81 --- /dev/null +++ b/devtools/client/responsive.html/reducers/location.js @@ -0,0 +1,25 @@ +/* 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 { CHANGE_LOCATION } = require("../actions/index"); + +const INITIAL_LOCATION = "about:blank"; + +const reducers = { + + [CHANGE_LOCATION](_, action) { + return action.location; + }, + +}; + +module.exports = function(location = INITIAL_LOCATION, action) { + const reducer = reducers[action.type]; + if (!reducer) { + return location; + } + return reducer(location, action); +}; diff --git a/devtools/client/responsive.html/reducers/moz.build b/devtools/client/responsive.html/reducers/moz.build index 3f2f60d74c1b..f7d191b6dadc 100644 --- a/devtools/client/responsive.html/reducers/moz.build +++ b/devtools/client/responsive.html/reducers/moz.build @@ -6,8 +6,11 @@ DevToolsModules( 'devices.js', + 'display-pixel-ratio.js', + 'location.js', 'reload-conditions.js', 'screenshot.js', + 'touch-simulation.js', 'ui.js', 'viewports.js', ) diff --git a/devtools/client/responsive.html/reducers/screenshot.js b/devtools/client/responsive.html/reducers/screenshot.js index e26380889d58..11246f5bddac 100644 --- a/devtools/client/responsive.html/reducers/screenshot.js +++ b/devtools/client/responsive.html/reducers/screenshot.js @@ -9,9 +9,7 @@ const { TAKE_SCREENSHOT_START, } = require("../actions/index"); -const INITIAL_SCREENSHOT = { - isCapturing: false, -}; +const INITIAL_SCREENSHOT = { isCapturing: false }; const reducers = { diff --git a/devtools/client/responsive.html/reducers/touch-simulation.js b/devtools/client/responsive.html/reducers/touch-simulation.js new file mode 100644 index 000000000000..6aebaa40d914 --- /dev/null +++ b/devtools/client/responsive.html/reducers/touch-simulation.js @@ -0,0 +1,31 @@ +/* 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 { + CHANGE_TOUCH_SIMULATION, +} = require("../actions/index"); + +const INITIAL_TOUCH_SIMULATION = { + enabled: false, +}; + +const reducers = { + + [CHANGE_TOUCH_SIMULATION](touchSimulation, { enabled }) { + return Object.assign({}, touchSimulation, { + enabled, + }); + }, + +}; + +module.exports = function(touchSimulation = INITIAL_TOUCH_SIMULATION, action) { + const reducer = reducers[action.type]; + if (!reducer) { + return touchSimulation; + } + return reducer(touchSimulation, action); +}; diff --git a/devtools/client/responsive.html/reducers/ui.js b/devtools/client/responsive.html/reducers/ui.js index 5f3c8f27ddb0..10e93e10f645 100644 --- a/devtools/client/responsive.html/reducers/ui.js +++ b/devtools/client/responsive.html/reducers/ui.js @@ -7,30 +7,18 @@ const Services = require("Services"); const { - CHANGE_DISPLAY_PIXEL_RATIO, TOGGLE_LEFT_ALIGNMENT, - TOGGLE_TOUCH_SIMULATION, } = require("../actions/index"); const LEFT_ALIGNMENT_ENABLED = "devtools.responsive.leftAlignViewport.enabled"; const INITIAL_UI = { - // The pixel ratio of the display. - displayPixelRatio: 0, // Whether or not the viewports are left aligned. leftAlignmentEnabled: Services.prefs.getBoolPref(LEFT_ALIGNMENT_ENABLED), - // Whether or not touch simulation is enabled. - touchSimulationEnabled: false, }; const reducers = { - [CHANGE_DISPLAY_PIXEL_RATIO](ui, { displayPixelRatio }) { - return Object.assign({}, ui, { - displayPixelRatio, - }); - }, - [TOGGLE_LEFT_ALIGNMENT](ui, { enabled }) { const leftAlignmentEnabled = enabled !== undefined ? enabled : !ui.leftAlignmentEnabled; @@ -42,12 +30,6 @@ const reducers = { }); }, - [TOGGLE_TOUCH_SIMULATION](ui, { enabled }) { - return Object.assign({}, ui, { - touchSimulationEnabled: enabled, - }); - }, - }; module.exports = function(ui = INITIAL_UI, action) { diff --git a/devtools/client/responsive.html/reducers/viewports.js b/devtools/client/responsive.html/reducers/viewports.js index f75ac146a28a..507b5610b0d3 100644 --- a/devtools/client/responsive.html/reducers/viewports.js +++ b/devtools/client/responsive.html/reducers/viewports.js @@ -22,7 +22,9 @@ const INITIAL_VIEWPORT = { deviceType: "", width: 320, height: 480, - pixelRatio: 0, + pixelRatio: { + value: 0, + }, userContextId: 0, }; @@ -58,7 +60,9 @@ const reducers = { } return Object.assign({}, viewport, { - pixelRatio, + pixelRatio: { + value: pixelRatio + }, }); }); }, diff --git a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js index 4e7799323242..5289ebe3a156 100644 --- a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js +++ b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js @@ -5,8 +5,8 @@ // Test changing the display pixel ratio. -const { changeDisplayPixelRatio } = require("devtools/client/responsive.html/actions/ui"); - +const { changeDisplayPixelRatio } = + require("devtools/client/responsive.html/actions/display-pixel-ratio"); const NEW_PIXEL_RATIO = 5.5; add_task(async function() { diff --git a/devtools/client/responsive.html/test/unit/test_change_location.js b/devtools/client/responsive.html/test/unit/test_change_location.js new file mode 100644 index 000000000000..f8d3274550c0 --- /dev/null +++ b/devtools/client/responsive.html/test/unit/test_change_location.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test changing the location of the displayed page. + +const { changeLocation } = + require("devtools/client/responsive.html/actions/location"); + +const TEST_URL = "http://example.com"; + +add_task(async function() { + const store = Store(); + const { getState, dispatch } = store; + + equal(getState().location, "about:blank", + "Defaults to about:blank at startup"); + + dispatch(changeLocation(TEST_URL)); + equal(getState().location, TEST_URL, "Location changed to TEST_URL"); +}); diff --git a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js index 63503250db4a..12ab4e2bcf61 100644 --- a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js +++ b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js @@ -5,7 +5,9 @@ // Test updating the touch simulation `enabled` property -const { toggleTouchSimulation } = require("devtools/client/responsive.html/actions/touch-simulation"); +const { + changeTouchSimulation, +} = require("devtools/client/responsive.html/actions/touch-simulation"); add_task(async function() { const store = Store(); @@ -14,7 +16,7 @@ add_task(async function() { ok(!getState().touchSimulation.enabled, "Touch simulation is disabled by default."); - dispatch(toggleTouchSimulation(true)); + dispatch(changeTouchSimulation(true)); ok(getState().touchSimulation.enabled, "Touch simulation is enabled."); diff --git a/devtools/client/responsive.html/test/unit/xpcshell.ini b/devtools/client/responsive.html/test/unit/xpcshell.ini index b5241660f4c0..432e68ed2030 100644 --- a/devtools/client/responsive.html/test/unit/xpcshell.ini +++ b/devtools/client/responsive.html/test/unit/xpcshell.ini @@ -8,6 +8,7 @@ firefox-appdir = browser [test_add_viewport.js] [test_change_device.js] [test_change_display_pixel_ratio.js] +[test_change_location.js] [test_change_network_throttling.js] [test_change_pixel_ratio.js] [test_resize_viewport.js] diff --git a/devtools/client/responsive.html/types.js b/devtools/client/responsive.html/types.js index 3130550a58e8..99d89cae6a9e 100644 --- a/devtools/client/responsive.html/types.js +++ b/devtools/client/responsive.html/types.js @@ -24,6 +24,11 @@ exports.loadableState = createEnum([ /* GLOBAL */ +/** + * The location of the document displayed in the viewport(s). + */ +exports.location = PropTypes.string; + /** * Whether to reload the page automatically when certain actions occur. */ @@ -125,6 +130,16 @@ exports.networkThrottling = { }; +/** + * Device pixel ratio for a given viewport. + */ +const pixelRatio = exports.pixelRatio = { + + // The device pixel ratio value + value: PropTypes.number, + +}; + /** * Touch simulation state for a given viewport. */ @@ -156,7 +171,7 @@ exports.viewport = { height: PropTypes.number, // The device pixel ratio of the viewport - pixelRatio: PropTypes.number, + pixelRatio: PropTypes.shape(pixelRatio), // The user context (container) ID for the viewport // Defaults to 0 meaning the default context From 15c023f2061e0e28701b6c59ad2de694ce6f7c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Tue, 4 Sep 2018 01:21:00 +0300 Subject: [PATCH 58/80] Bug 1487295 - Add defaults to PaymentMethodChangeEventInit's members. r=baku --- dom/payments/PaymentMethodChangeEvent.cpp | 4 +--- dom/payments/PaymentMethodChangeEvent.h | 1 + dom/webidl/PaymentMethodChangeEvent.webidl | 4 ++-- testing/web-platform/meta/MANIFEST.json | 4 ++-- .../methodDetails-attribute.https.html | 11 +++++++++++ .../methodName-attribute.https.html | 11 +++++++++++ 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/dom/payments/PaymentMethodChangeEvent.cpp b/dom/payments/PaymentMethodChangeEvent.cpp index c2030469d70a..8ce0b1473fa4 100644 --- a/dom/payments/PaymentMethodChangeEvent.cpp +++ b/dom/payments/PaymentMethodChangeEvent.cpp @@ -72,9 +72,7 @@ PaymentMethodChangeEvent::init( const PaymentMethodChangeEventInit& aEventInitDict) { mMethodName.Assign(aEventInitDict.mMethodName); - if (aEventInitDict.mMethodDetails.WasPassed()) { - mMethodDetails = aEventInitDict.mMethodDetails.Value(); - } + mMethodDetails = aEventInitDict.mMethodDetails; } void diff --git a/dom/payments/PaymentMethodChangeEvent.h b/dom/payments/PaymentMethodChangeEvent.h index a7a07eb36397..9518825e2821 100644 --- a/dom/payments/PaymentMethodChangeEvent.h +++ b/dom/payments/PaymentMethodChangeEvent.h @@ -14,6 +14,7 @@ namespace mozilla { namespace dom { class PaymentRequestUpdateEvent; +struct PaymentMethodChangeEventInit; class PaymentMethodChangeEvent final : public PaymentRequestUpdateEvent { public: diff --git a/dom/webidl/PaymentMethodChangeEvent.webidl b/dom/webidl/PaymentMethodChangeEvent.webidl index 551e6042141d..0d80dbf49900 100644 --- a/dom/webidl/PaymentMethodChangeEvent.webidl +++ b/dom/webidl/PaymentMethodChangeEvent.webidl @@ -8,6 +8,6 @@ interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent { }; dictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit { - required DOMString methodName; - object? methodDetails; + DOMString methodName = ""; + object? methodDetails = null; }; diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 20935804299d..1be9c8dc4fb8 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -620617,11 +620617,11 @@ "testharness" ], "payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html": [ - "a478c559d497e8dea9d471ce1e36427bfb741aa7", + "ec0aa96dddb46b26617064ab54e9d02e2a588cbb", "testharness" ], "payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html": [ - "e6e0bf9a91971b3a20acf59cf27097281f0d2085", + "176638c7852f6f0f8fd7a8c3dfefdf439a829d22", "testharness" ], "payment-request/PaymentRequestUpdateEvent/constructor.http.html": [ diff --git a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html index a478c559d497..ec0aa96dddb4 100644 --- a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html +++ b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html @@ -19,4 +19,15 @@ test(() => { assert_equals(test, "pass"); assert_equals(event.methodDetails, methodDetails); }, "Must have a methodDetails IDL attribute, which is initialized with to the methodName dictionary value"); + +test(() => { + const event = new PaymentMethodChangeEvent("test"); + assert_equals(event.methodDetails, null, "methodDetails attribute must initialize to null"); + + const event2 = new PaymentMethodChangeEvent("test", { methodName: "basic-card" }); + assert_equals(event2.methodDetails, null, "methodDetails attribute must initialize to null"); + + const event3 = new PaymentMethodChangeEvent("test", {}); + assert_equals(event2.methodDetails, null, "methodDetails attribute must initialize to null"); +}, "The methodDetails member defaults to null"); diff --git a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html index e6e0bf9a9197..176638c7852f 100644 --- a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html +++ b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html @@ -14,4 +14,15 @@ test(() => { const { methodName } = event; assert_equals(methodName, "wpt-test"); }, "Must have a methodName IDL attribute, which is initialized with to the methodName dictionary value"); + +test(() => { + const event = new PaymentMethodChangeEvent("test"); + assert_equals(event.methodName, "", "methodName attribute must initialize to empty string"); + + const event2 = new PaymentMethodChangeEvent("test", { methodDetails: {} }); + assert_equals(event2.methodName, "", "methodName attribute must initialize to empty string"); + + const event3 = new PaymentMethodChangeEvent("test", {}); + assert_equals(event3.methodName, "", "methodName attribute must initialize to empty string"); +}, "When no dictionary is passed, the methodName member defaults to the empty string"); From 04ac107fa05d7bb3853dcf605087573c265cdacb Mon Sep 17 00:00:00 2001 From: Diego Pino Garcia Date: Mon, 3 Sep 2018 03:20:00 +0300 Subject: [PATCH 59/80] Bug 1486125 - Remove JSContext::noGCOrAllocationCheck and its helper methods. r=jonco --- js/src/gc/Allocator.cpp | 1 - js/src/gc/GC.cpp | 2 -- js/src/vm/BytecodeUtil.cpp | 6 +----- js/src/vm/JSContext.cpp | 1 - js/src/vm/JSContext.h | 8 -------- 5 files changed, 1 insertion(+), 17 deletions(-) diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp index 0a54092a4bd9..ce495f90edba 100644 --- a/js/src/gc/Allocator.cpp +++ b/js/src/gc/Allocator.cpp @@ -291,7 +291,6 @@ GCRuntime::checkAllocatorState(JSContext* cx, AllocKind kind) kind != AllocKind::ATOM && kind != AllocKind::FAT_INLINE_ATOM); MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); - MOZ_ASSERT(cx->isAllocAllowed()); #endif // Crash if we perform a GC action when it is not safe. diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 6290b7d2993c..9d66928f9947 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -7689,8 +7689,6 @@ GCRuntime::checkCanCallAPI() /* If we attempt to invoke the GC while we are running in the GC, assert. */ MOZ_RELEASE_ASSERT(!JS::RuntimeHeapIsBusy()); - - MOZ_ASSERT(rt->mainContextFromOwnThread()->isAllocAllowed()); } bool diff --git a/js/src/vm/BytecodeUtil.cpp b/js/src/vm/BytecodeUtil.cpp index 369a6b0ca1c3..b7235a682d1a 100644 --- a/js/src/vm/BytecodeUtil.cpp +++ b/js/src/vm/BytecodeUtil.cpp @@ -1150,11 +1150,7 @@ ToDisassemblySource(JSContext* cx, HandleValue v, JSAutoByteString* bytes) return true; } - if (JS::RuntimeHeapIsBusy() -#ifdef DEBUG - || !cx->isAllocAllowed() -#endif - ) { + if (JS::RuntimeHeapIsBusy()) { UniqueChars source = JS_smprintf(""); if (!source) { ReportOutOfMemory(cx); diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp index 87dda1662287..ae37ae76a93d 100644 --- a/js/src/vm/JSContext.cpp +++ b/js/src/vm/JSContext.cpp @@ -1293,7 +1293,6 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options) gcSweeping(false), gcHelperStateThread(false), isTouchingGrayThings(false), - noGCOrAllocationCheck(0), noNurseryAllocationCheck(0), disableStrictProxyCheckingCount(0), #endif diff --git a/js/src/vm/JSContext.h b/js/src/vm/JSContext.h index fd0c4cae9e87..887db02bba79 100644 --- a/js/src/vm/JSContext.h +++ b/js/src/vm/JSContext.h @@ -544,7 +544,6 @@ struct JSContext : public JS::RootingContext, // Whether this thread is currently manipulating possibly-gray GC things. js::ThreadData isTouchingGrayThings; - js::ThreadData noGCOrAllocationCheck; js::ThreadData noNurseryAllocationCheck; /* @@ -555,13 +554,6 @@ struct JSContext : public JS::RootingContext, */ js::ThreadData disableStrictProxyCheckingCount; - bool isAllocAllowed() { return noGCOrAllocationCheck == 0; } - void disallowAlloc() { ++noGCOrAllocationCheck; } - void allowAlloc() { - MOZ_ASSERT(!isAllocAllowed()); - --noGCOrAllocationCheck; - } - bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; } void disallowNurseryAlloc() { ++noNurseryAllocationCheck; } void allowNurseryAlloc() { From c62b5868437cc46a65207c84b7a6aa293bf682cc Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Tue, 4 Sep 2018 18:50:16 +0200 Subject: [PATCH 60/80] Bug 1487600 - Report to console any content blocking, r=ehsan --- netwerk/locales/en-US/necko.properties | 5 ++ .../antitracking/AntiTrackingCommon.cpp | 77 ++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/netwerk/locales/en-US/necko.properties b/netwerk/locales/en-US/necko.properties index f51e5b359e79..05286793a150 100644 --- a/netwerk/locales/en-US/necko.properties +++ b/netwerk/locales/en-US/necko.properties @@ -42,6 +42,11 @@ AutomaticAuth=You are about to log in to the site “%1$S” with the username TrackerUriBlocked=The resource at “%1$S” was blocked because content blocking is enabled. UnsafeUriBlocked=The resource at “%1$S” was blocked by Safe Browsing. +CookieBlockedByPermission=Request to access cookies or storage on “%1$S” was blocked because of custom cookie permission. +CookieBlockedTracker=Request to access cookie or storage on “%1$S” was blocked because it came from a tracker and content blocking is enabled. +CookieBlockedAll=Request to access cookie or storage on “%1$S” was blocked because we are blocking all storage access requests. +CookieBlockedForeign=Request to access cookie or storage on “%1$S” was blocked because we are blocking all third-party storage access requests and content blocking is enabled. +CookieBlockedSlowTrackingContent=The resource at “%1$S” was blocked because content blocking is enabled and the resource was classified as a slow tracking resource. # LOCALIZATION NOTE (nsICookieManagerAPIDeprecated): don't localize originAttributes. # %1$S is the deprecated API; %2$S is the interface suffix that the given deprecated API belongs to. diff --git a/toolkit/components/antitracking/AntiTrackingCommon.cpp b/toolkit/components/antitracking/AntiTrackingCommon.cpp index b109785bedc1..52bc59f34722 100644 --- a/toolkit/components/antitracking/AntiTrackingCommon.cpp +++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp @@ -17,11 +17,13 @@ #include "nsGlobalWindowInner.h" #include "nsICookiePermission.h" #include "nsICookieService.h" +#include "nsIDocShell.h" #include "nsIHttpChannelInternal.h" #include "nsIIOService.h" #include "nsIParentChannel.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" +#include "nsIScriptError.h" #include "nsIURI.h" #include "nsIURL.h" #include "nsIWebProgressListener.h" @@ -186,6 +188,71 @@ CheckContentBlockingAllowList(nsIHttpChannel* aChannel) return false; } +void +ReportBlockingToConsole(nsPIDOMWindowOuter* aWindow, nsIHttpChannel* aChannel, + int64_t aRejectedReason) +{ + MOZ_ASSERT(aWindow && aChannel); + MOZ_ASSERT(aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION || + aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER || + aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL || + aRejectedReason == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN || + aRejectedReason == nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT); + + if (!StaticPrefs::browser_contentblocking_enabled()) { + return; + } + + nsCOMPtr docShell = aWindow->GetDocShell(); + if (NS_WARN_IF(!docShell)) { + return; + } + + nsCOMPtr doc = docShell->GetDocument(); + if (NS_WARN_IF(!doc)) { + return; + } + + const char* message = nullptr; + switch (aRejectedReason) { + case nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION: + message = "CookieBlockedByPermission"; + break; + + case nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER: + message = "CookieBlockedTracker"; + break; + + case nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL: + message = "CookieBlockedAll"; + break; + + case nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN: + message = "CookieBlockedForeign"; + break; + + case nsIWebProgressListener::STATE_BLOCKED_SLOW_TRACKING_CONTENT: + message = "CookieBlockedSlowTrackingContent"; + break; + + default: + return; + } + + MOZ_ASSERT(message); + + nsCOMPtr uri; + aChannel->GetURI(getter_AddRefs(uri)); + NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault()); + const char16_t* params[] = { spec.get() }; + + nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, + NS_LITERAL_CSTRING("Content Blocking"), + doc, + nsContentUtils::eNECKO_PROPERTIES, + message, + params, ArrayLength(params)); +} } // anonymous /* static */ RefPtr @@ -916,6 +983,8 @@ AntiTrackingCommon::NotifyRejection(nsIChannel* aChannel, } pwin->NotifyContentBlockingState(aRejectedReason, aChannel); + + ReportBlockingToConsole(pwin, httpChannel, aRejectedReason); } /* static */ void @@ -946,7 +1015,11 @@ AntiTrackingCommon::NotifyRejection(nsPIDOMWindowInner* aWindow, pwin = outer->GetTopOuter(); } - if (pwin) { - pwin->NotifyContentBlockingState(aRejectedReason, httpChannel); + if (!pwin) { + return; } + + pwin->NotifyContentBlockingState(aRejectedReason, httpChannel); + + ReportBlockingToConsole(pwin, httpChannel, aRejectedReason); } From 75e60e08dacc2a155ebca48d24e4da54ac3e7939 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Tue, 4 Sep 2018 10:47:41 -0400 Subject: [PATCH 61/80] Bug 1488114 - Refactor the reducers in RDM. r=rcaliman --- .../locales/en-US/responsive.properties | 7 ++--- .../client/responsive.html/actions/devices.js | 3 +- .../actions/display-pixel-ratio.js | 23 -------------- .../client/responsive.html/actions/index.js | 12 +++---- .../responsive.html/actions/location.js | 22 ------------- .../client/responsive.html/actions/moz.build | 3 -- .../actions/reload-conditions.js | 3 +- .../responsive.html/actions/screenshot.js | 3 +- .../actions/touch-simulation.js | 22 ------------- devtools/client/responsive.html/actions/ui.js | 21 +++++++++++++ .../client/responsive.html/browser/swap.js | 2 +- .../responsive.html/browser/web-navigation.js | 1 + .../client/responsive.html/components/App.js | 22 ++++++------- .../components/DevicePixelRatioMenu.js | 10 +++--- .../components/ResizableViewport.js | 4 +-- .../responsive.html/components/Toolbar.js | 16 +++++----- .../components/ViewportDimension.js | 4 +-- .../responsive.html/components/Viewports.js | 6 ++-- devtools/client/responsive.html/index.js | 4 +-- devtools/client/responsive.html/manager.js | 5 ++- devtools/client/responsive.html/reducers.js | 3 -- .../responsive.html/reducers/devices.js | 4 +-- .../reducers/display-pixel-ratio.js | 26 ---------------- .../responsive.html/reducers/location.js | 25 --------------- .../client/responsive.html/reducers/moz.build | 3 -- .../responsive.html/reducers/screenshot.js | 4 ++- .../reducers/touch-simulation.js | 31 ------------------- .../client/responsive.html/reducers/ui.js | 18 +++++++++++ .../responsive.html/reducers/viewports.js | 8 ++--- .../unit/test_change_display_pixel_ratio.js | 8 ++--- .../test/unit/test_change_location.js | 22 ------------- .../test/unit/test_change_pixel_ratio.js | 2 +- .../test_update_touch_simulation_enabled.js | 10 +++--- .../responsive.html/test/unit/xpcshell.ini | 1 - devtools/client/responsive.html/types.js | 17 +--------- 35 files changed, 106 insertions(+), 269 deletions(-) delete mode 100644 devtools/client/responsive.html/actions/display-pixel-ratio.js delete mode 100644 devtools/client/responsive.html/actions/location.js delete mode 100644 devtools/client/responsive.html/actions/touch-simulation.js delete mode 100644 devtools/client/responsive.html/reducers/display-pixel-ratio.js delete mode 100644 devtools/client/responsive.html/reducers/location.js delete mode 100644 devtools/client/responsive.html/reducers/touch-simulation.js delete mode 100644 devtools/client/responsive.html/test/unit/test_change_location.js diff --git a/devtools/client/locales/en-US/responsive.properties b/devtools/client/locales/en-US/responsive.properties index 6e2ede4ee46c..aaa9c524a8d1 100644 --- a/devtools/client/locales/en-US/responsive.properties +++ b/devtools/client/locales/en-US/responsive.properties @@ -124,10 +124,9 @@ responsive.reloadConditions.touchSimulation=Reload when touch simulation is togg # to select whether to reload when user agent is changed. responsive.reloadConditions.userAgent=Reload when user agent is changed -# LOCALIZATION NOTE (responsive.reloadNotification.description): Text in notification bar -# shown on first open to clarify that some features need a reload to apply. %1$S is the -# label on the reload conditions menu (responsive.reloadConditions.label). -responsive.reloadNotification.description=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the “%1$S” menu. +# LOCALIZATION NOTE (responsive.reloadNotification.description2): Text in notification bar +# shown on first open to clarify that some features need a reload to apply. +responsive.reloadNotification.description2=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the Settings menu. # LOCALIZATION NOTE (responsive.leftAlignViewport): Label on checkbox used in the settings # menu. diff --git a/devtools/client/responsive.html/actions/devices.js b/devtools/client/responsive.html/actions/devices.js index 13a8fc4ccb05..0726596d95eb 100644 --- a/devtools/client/responsive.html/actions/devices.js +++ b/devtools/client/responsive.html/actions/devices.js @@ -4,6 +4,8 @@ "use strict"; +const Services = require("Services"); + const { ADD_DEVICE, ADD_DEVICE_TYPE, @@ -18,7 +20,6 @@ const { removeDeviceAssociation } = require("./viewports"); const { addDevice, getDevices, removeDevice } = require("devtools/client/shared/devices"); -const Services = require("Services"); const DISPLAYED_DEVICES_PREF = "devtools.responsive.html.displayedDeviceList"; /** diff --git a/devtools/client/responsive.html/actions/display-pixel-ratio.js b/devtools/client/responsive.html/actions/display-pixel-ratio.js deleted file mode 100644 index ff3343bb5d02..000000000000 --- a/devtools/client/responsive.html/actions/display-pixel-ratio.js +++ /dev/null @@ -1,23 +0,0 @@ -/* 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 { CHANGE_DISPLAY_PIXEL_RATIO } = require("./index"); - -module.exports = { - - /** - * The pixel ratio of the display has changed. This may be triggered by the user - * when changing the monitor resolution, or when the window is dragged to a different - * display with a different pixel ratio. - */ - changeDisplayPixelRatio(displayPixelRatio) { - return { - type: CHANGE_DISPLAY_PIXEL_RATIO, - displayPixelRatio, - }; - }, - -}; diff --git a/devtools/client/responsive.html/actions/index.js b/devtools/client/responsive.html/actions/index.js index 0db4d70e1254..5306161dd6f1 100644 --- a/devtools/client/responsive.html/actions/index.js +++ b/devtools/client/responsive.html/actions/index.js @@ -4,9 +4,9 @@ "use strict"; -// This file lists all of the actions available in responsive design. This +// This file lists all of the actions available in responsive design. This // central list of constants makes it easy to see all possible action names at -// a glance. Please add a comment with each new action type. +// a glance. Please add a comment with each new action type. const { createEnum } = require("devtools/client/shared/enum"); @@ -28,7 +28,7 @@ createEnum([ // Change the device displayed in the viewport. "CHANGE_DEVICE", - // Change the location of the page. This may be triggered by the user + // Change the location of the page. This may be triggered by the user // directly entering a new URL, navigating with links, etc. "CHANGE_LOCATION", @@ -48,9 +48,6 @@ createEnum([ // Change one of the reload conditions. "CHANGE_RELOAD_CONDITION", - // Change the touch simulation state. - "CHANGE_TOUCH_SIMULATION", - // Indicates that the device list is being loaded. "LOAD_DEVICE_LIST_START", @@ -84,6 +81,9 @@ createEnum([ // Toggles the left alignment of the viewports. "TOGGLE_LEFT_ALIGNMENT", + // Toggles the touch simulation state of the viewports. + "TOGGLE_TOUCH_SIMULATION", + // Update the device display state in the device selector. "UPDATE_DEVICE_DISPLAYED", diff --git a/devtools/client/responsive.html/actions/location.js b/devtools/client/responsive.html/actions/location.js deleted file mode 100644 index 565825e5e655..000000000000 --- a/devtools/client/responsive.html/actions/location.js +++ /dev/null @@ -1,22 +0,0 @@ -/* 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 { CHANGE_LOCATION } = require("./index"); - -module.exports = { - - /** - * The location of the page has changed. This may be triggered by the user - * directly entering a new URL, navigating with links, etc. - */ - changeLocation(location) { - return { - type: CHANGE_LOCATION, - location, - }; - }, - -}; diff --git a/devtools/client/responsive.html/actions/moz.build b/devtools/client/responsive.html/actions/moz.build index 26e34ff8b0da..ae665ef2348b 100644 --- a/devtools/client/responsive.html/actions/moz.build +++ b/devtools/client/responsive.html/actions/moz.build @@ -6,12 +6,9 @@ DevToolsModules( 'devices.js', - 'display-pixel-ratio.js', 'index.js', - 'location.js', 'reload-conditions.js', 'screenshot.js', - 'touch-simulation.js', 'ui.js', 'viewports.js', ) diff --git a/devtools/client/responsive.html/actions/reload-conditions.js b/devtools/client/responsive.html/actions/reload-conditions.js index 732f8a738166..22485a14e98f 100644 --- a/devtools/client/responsive.html/actions/reload-conditions.js +++ b/devtools/client/responsive.html/actions/reload-conditions.js @@ -4,13 +4,14 @@ "use strict"; +const Services = require("Services"); + const { CHANGE_RELOAD_CONDITION, LOAD_RELOAD_CONDITIONS_END, } = require("./index"); const Types = require("../types"); -const Services = require("Services"); const PREF_PREFIX = "devtools.responsive.reloadConditions."; diff --git a/devtools/client/responsive.html/actions/screenshot.js b/devtools/client/responsive.html/actions/screenshot.js index 482eff85b8c1..317ae23e00a1 100644 --- a/devtools/client/responsive.html/actions/screenshot.js +++ b/devtools/client/responsive.html/actions/screenshot.js @@ -6,6 +6,8 @@ "use strict"; +const Services = require("Services"); + const { TAKE_SCREENSHOT_START, TAKE_SCREENSHOT_END, @@ -14,7 +16,6 @@ const { const { getFormatStr } = require("../utils/l10n"); const { getTopLevelWindow } = require("../utils/window"); const e10s = require("../utils/e10s"); -const Services = require("Services"); const CAMERA_AUDIO_URL = "resource://devtools/client/themes/audio/shutter.wav"; diff --git a/devtools/client/responsive.html/actions/touch-simulation.js b/devtools/client/responsive.html/actions/touch-simulation.js deleted file mode 100644 index 8f98101e7a78..000000000000 --- a/devtools/client/responsive.html/actions/touch-simulation.js +++ /dev/null @@ -1,22 +0,0 @@ -/* 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/. */ - -/* eslint-env browser */ - -"use strict"; - -const { - CHANGE_TOUCH_SIMULATION -} = require("./index"); - -module.exports = { - - changeTouchSimulation(enabled) { - return { - type: CHANGE_TOUCH_SIMULATION, - enabled, - }; - }, - -}; diff --git a/devtools/client/responsive.html/actions/ui.js b/devtools/client/responsive.html/actions/ui.js index 22399f294290..95abe2bf3c1b 100644 --- a/devtools/client/responsive.html/actions/ui.js +++ b/devtools/client/responsive.html/actions/ui.js @@ -5,11 +5,25 @@ "use strict"; const { + CHANGE_DISPLAY_PIXEL_RATIO, TOGGLE_LEFT_ALIGNMENT, + TOGGLE_TOUCH_SIMULATION, } = require("./index"); module.exports = { + /** + * The pixel ratio of the display has changed. This may be triggered by the user + * when changing the monitor resolution, or when the window is dragged to a different + * display with a different pixel ratio. + */ + changeDisplayPixelRatio(displayPixelRatio) { + return { + type: CHANGE_DISPLAY_PIXEL_RATIO, + displayPixelRatio, + }; + }, + toggleLeftAlignment(enabled) { return { type: TOGGLE_LEFT_ALIGNMENT, @@ -17,4 +31,11 @@ module.exports = { }; }, + toggleTouchSimulation(enabled) { + return { + type: TOGGLE_TOUCH_SIMULATION, + enabled, + }; + }, + }; diff --git a/devtools/client/responsive.html/browser/swap.js b/devtools/client/responsive.html/browser/swap.js index 3287ce743426..b3d79701110f 100644 --- a/devtools/client/responsive.html/browser/swap.js +++ b/devtools/client/responsive.html/browser/swap.js @@ -5,9 +5,9 @@ "use strict"; const { Ci } = require("chrome"); +const Services = require("Services"); const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm"); const { tunnelToInnerBrowser } = require("./tunnel"); -const Services = require("Services"); function debug(msg) { // console.log(`RDM swap: ${msg}`); diff --git a/devtools/client/responsive.html/browser/web-navigation.js b/devtools/client/responsive.html/browser/web-navigation.js index f28f26ce9b6b..c82973201d09 100644 --- a/devtools/client/responsive.html/browser/web-navigation.js +++ b/devtools/client/responsive.html/browser/web-navigation.js @@ -10,6 +10,7 @@ const Services = require("Services"); const { NetUtil } = require("resource://gre/modules/NetUtil.jsm"); const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm"); const Telemetry = require("devtools/client/shared/telemetry"); + const telemetry = new Telemetry(); function readInputStreamToString(stream) { diff --git a/devtools/client/responsive.html/components/App.js b/devtools/client/responsive.html/components/App.js index e25a26fbef61..d4413a8f8f2d 100644 --- a/devtools/client/responsive.html/components/App.js +++ b/devtools/client/responsive.html/components/App.js @@ -6,7 +6,7 @@ "use strict"; -const { Component, createFactory } = require("devtools/client/shared/vendor/react"); +const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { connect } = require("devtools/client/shared/vendor/react-redux"); @@ -27,8 +27,10 @@ const { } = require("../actions/devices"); const { changeReloadCondition } = require("../actions/reload-conditions"); const { takeScreenshot } = require("../actions/screenshot"); -const { changeTouchSimulation } = require("../actions/touch-simulation"); -const { toggleLeftAlignment } = require("../actions/ui"); +const { + toggleTouchSimulation, + toggleLeftAlignment, +} = require("../actions/ui"); const { changeDevice, changePixelRatio, @@ -39,16 +41,14 @@ const { const Types = require("../types"); -class App extends Component { +class App extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, dispatch: PropTypes.func.isRequired, - displayPixelRatio: Types.pixelRatio.value.isRequired, networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired, reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired, screenshot: PropTypes.shape(Types.screenshot).isRequired, - touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired, viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired, }; } @@ -93,7 +93,7 @@ class App extends Component { device, }, "*"); this.props.dispatch(changeDevice(id, device.name, deviceType)); - this.props.dispatch(changeTouchSimulation(device.touch)); + this.props.dispatch(toggleTouchSimulation(device.touch)); this.props.dispatch(changePixelRatio(id, device.pixelRatio)); } @@ -123,7 +123,7 @@ class App extends Component { type: "change-touch-simulation", enabled, }, "*"); - this.props.dispatch(changeTouchSimulation(enabled)); + this.props.dispatch(toggleTouchSimulation(enabled)); } onContentResize({ width, height }) { @@ -150,7 +150,7 @@ class App extends Component { // TODO: Bug 1332754: Move messaging and logic into the action creator so that device // property changes are sent from there instead of this function. this.props.dispatch(removeDeviceAssociation(id)); - this.props.dispatch(changeTouchSimulation(false)); + this.props.dispatch(toggleTouchSimulation(false)); this.props.dispatch(changePixelRatio(id, 0)); } @@ -181,11 +181,9 @@ class App extends Component { render() { const { devices, - displayPixelRatio, networkThrottling, reloadConditions, screenshot, - touchSimulation, viewports, } = this.props; @@ -226,13 +224,11 @@ class App extends Component { dom.div({ id: "app" }, Toolbar({ devices, - displayPixelRatio, networkThrottling, reloadConditions, screenshot, selectedDevice, selectedPixelRatio, - touchSimulation, viewport: viewports[0], onChangeDevice, onChangeNetworkThrottling, diff --git a/devtools/client/responsive.html/components/DevicePixelRatioMenu.js b/devtools/client/responsive.html/components/DevicePixelRatioMenu.js index 75fa97d553e5..473e6c65d235 100644 --- a/devtools/client/responsive.html/components/DevicePixelRatioMenu.js +++ b/devtools/client/responsive.html/components/DevicePixelRatioMenu.js @@ -21,10 +21,10 @@ class DevicePixelRatioMenu extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, - displayPixelRatio: Types.pixelRatio.value.isRequired, + displayPixelRatio: PropTypes.number.isRequired, onChangePixelRatio: PropTypes.func.isRequired, selectedDevice: PropTypes.string.isRequired, - selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired, + selectedPixelRatio: PropTypes.number.isRequired, }; } @@ -44,8 +44,8 @@ class DevicePixelRatioMenu extends PureComponent { return { label: getFormatStr("responsive.devicePixelRatioOption", value), type: "checkbox", - checked: selectedPixelRatio.value > 0 ? - selectedPixelRatio.value === value : + checked: selectedPixelRatio > 0 ? + selectedPixelRatio === value : displayPixelRatio === value, click: () => onChangePixelRatio(+value), }; @@ -86,7 +86,7 @@ class DevicePixelRatioMenu extends PureComponent { }, dom.span({ className: "title" }, getFormatStr("responsive.devicePixelRatioOption", - selectedPixelRatio.value || displayPixelRatio) + selectedPixelRatio || displayPixelRatio) ) ) ); diff --git a/devtools/client/responsive.html/components/ResizableViewport.js b/devtools/client/responsive.html/components/ResizableViewport.js index eefcf5c72206..22120938990c 100644 --- a/devtools/client/responsive.html/components/ResizableViewport.js +++ b/devtools/client/responsive.html/components/ResizableViewport.js @@ -6,7 +6,7 @@ "use strict"; -const { Component, createFactory } = require("devtools/client/shared/vendor/react"); +const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); @@ -18,7 +18,7 @@ const Types = require("../types"); const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION; const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION; -class ResizableViewport extends Component { +class ResizableViewport extends PureComponent { static get propTypes() { return { leftAlignmentEnabled: PropTypes.bool.isRequired, diff --git a/devtools/client/responsive.html/components/Toolbar.js b/devtools/client/responsive.html/components/Toolbar.js index b50162302872..ce50e0cec769 100644 --- a/devtools/client/responsive.html/components/Toolbar.js +++ b/devtools/client/responsive.html/components/Toolbar.js @@ -22,7 +22,7 @@ class Toolbar extends PureComponent { static get propTypes() { return { devices: PropTypes.shape(Types.devices).isRequired, - displayPixelRatio: Types.pixelRatio.value.isRequired, + displayPixelRatio: PropTypes.number.isRequired, leftAlignmentEnabled: PropTypes.bool.isRequired, networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired, onChangeDevice: PropTypes.func.isRequired, @@ -40,8 +40,8 @@ class Toolbar extends PureComponent { reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired, screenshot: PropTypes.shape(Types.screenshot).isRequired, selectedDevice: PropTypes.string.isRequired, - selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired, - touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired, + selectedPixelRatio: PropTypes.number.isRequired, + touchSimulationEnabled: PropTypes.bool.isRequired, viewport: PropTypes.shape(Types.viewport).isRequired, }; } @@ -68,7 +68,7 @@ class Toolbar extends PureComponent { screenshot, selectedDevice, selectedPixelRatio, - touchSimulation, + touchSimulationEnabled, viewport, } = this.props; @@ -121,10 +121,10 @@ class Toolbar extends PureComponent { dom.button({ id: "touch-simulation-button", className: "devtools-button" + - (touchSimulation.enabled ? " checked" : ""), - title: (touchSimulation.enabled ? + (touchSimulationEnabled ? " checked" : ""), + title: (touchSimulationEnabled ? getStr("responsive.disableTouch") : getStr("responsive.enableTouch")), - onClick: () => onChangeTouchSimulation(!touchSimulation.enabled), + onClick: () => onChangeTouchSimulation(!touchSimulationEnabled), }) ), dom.div( @@ -156,7 +156,9 @@ class Toolbar extends PureComponent { const mapStateToProps = state => { return { + displayPixelRatio: state.ui.displayPixelRatio, leftAlignmentEnabled: state.ui.leftAlignmentEnabled, + touchSimulationEnabled: state.ui.touchSimulationEnabled, }; }; diff --git a/devtools/client/responsive.html/components/ViewportDimension.js b/devtools/client/responsive.html/components/ViewportDimension.js index 6283427f82ac..f21576bbd363 100644 --- a/devtools/client/responsive.html/components/ViewportDimension.js +++ b/devtools/client/responsive.html/components/ViewportDimension.js @@ -4,7 +4,7 @@ "use strict"; -const { Component } = require("devtools/client/shared/vendor/react"); +const { PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); @@ -12,7 +12,7 @@ const { isKeyIn } = require("../utils/key"); const { MIN_VIEWPORT_DIMENSION } = require("../constants"); const Types = require("../types"); -class ViewportDimension extends Component { +class ViewportDimension extends PureComponent { static get propTypes() { return { onResizeViewport: PropTypes.func.isRequired, diff --git a/devtools/client/responsive.html/components/Viewports.js b/devtools/client/responsive.html/components/Viewports.js index 18aca2230417..dcdb3bb0ae6e 100644 --- a/devtools/client/responsive.html/components/Viewports.js +++ b/devtools/client/responsive.html/components/Viewports.js @@ -4,16 +4,16 @@ "use strict"; -const { connect } = require("devtools/client/shared/vendor/react-redux"); -const { Component, createFactory } = require("devtools/client/shared/vendor/react"); +const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react"); const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); +const { connect } = require("devtools/client/shared/vendor/react-redux"); const ResizableViewport = createFactory(require("./ResizableViewport")); const Types = require("../types"); -class Viewports extends Component { +class Viewports extends PureComponent { static get propTypes() { return { leftAlignmentEnabled: PropTypes.bool.isRequired, diff --git a/devtools/client/responsive.html/index.js b/devtools/client/responsive.html/index.js index a4207182b17c..7248f8b7638b 100644 --- a/devtools/client/responsive.html/index.js +++ b/devtools/client/responsive.html/index.js @@ -23,10 +23,9 @@ const message = require("./utils/message"); const App = createFactory(require("./components/App")); const Store = require("./store"); const { loadDevices } = require("./actions/devices"); -const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio"); -const { changeLocation } = require("./actions/location"); const { loadReloadConditions } = require("./actions/reload-conditions"); const { addViewport, resizeViewport } = require("./actions/viewports"); +const { changeDisplayPixelRatio } = require("./actions/ui"); // Exposed for use by tests window.require = require; @@ -117,7 +116,6 @@ function onDevicePixelRatioChange() { window.addInitialViewport = ({ uri, userContextId }) => { try { onDevicePixelRatioChange(); - bootstrap.dispatch(changeLocation(uri)); bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio)); bootstrap.dispatch(addViewport(userContextId)); } catch (e) { diff --git a/devtools/client/responsive.html/manager.js b/devtools/client/responsive.html/manager.js index 931a619f64df..df5d6f5909e9 100644 --- a/devtools/client/responsive.html/manager.js +++ b/devtools/client/responsive.html/manager.js @@ -491,8 +491,7 @@ ResponsiveUI.prototype = { showReloadNotification() { if (Services.prefs.getBoolPref(RELOAD_NOTIFICATION_PREF, false)) { showNotification(this.browserWindow, this.tab, { - msg: l10n.getFormatStr("responsive.reloadNotification.description", - l10n.getStr("responsive.reloadConditions.label")), + msg: l10n.getFormatStr("responsive.reloadNotification.description2"), }); Services.prefs.setBoolPref(RELOAD_NOTIFICATION_PREF, false); } @@ -581,7 +580,7 @@ ResponsiveUI.prototype = { async onChangeTouchSimulation(event) { const { enabled } = event.data; const reloadNeeded = await this.updateTouchSimulation(enabled) && - this.reloadOnChange("touchSimulation"); + this.reloadOnChange("touchSimulation"); if (reloadNeeded) { this.getViewportBrowser().reload(); } diff --git a/devtools/client/responsive.html/reducers.js b/devtools/client/responsive.html/reducers.js index f4f36d11db1d..e8fe16089eeb 100644 --- a/devtools/client/responsive.html/reducers.js +++ b/devtools/client/responsive.html/reducers.js @@ -5,11 +5,8 @@ "use strict"; exports.devices = require("./reducers/devices"); -exports.displayPixelRatio = require("./reducers/display-pixel-ratio"); -exports.location = require("./reducers/location"); exports.networkThrottling = require("devtools/client/shared/components/throttling/reducer"); exports.reloadConditions = require("./reducers/reload-conditions"); exports.screenshot = require("./reducers/screenshot"); -exports.touchSimulation = require("./reducers/touch-simulation"); exports.ui = require("./reducers/ui"); exports.viewports = require("./reducers/viewports"); diff --git a/devtools/client/responsive.html/reducers/devices.js b/devtools/client/responsive.html/reducers/devices.js index d42251d3bdb6..45544e8cfae4 100644 --- a/devtools/client/responsive.html/reducers/devices.js +++ b/devtools/client/responsive.html/reducers/devices.js @@ -18,10 +18,10 @@ const { const Types = require("../types"); const INITIAL_DEVICES = { - types: [], isModalOpen: false, - modalOpenedFromViewport: null, listState: Types.loadableState.INITIALIZED, + modalOpenedFromViewport: null, + types: [], }; const reducers = { diff --git a/devtools/client/responsive.html/reducers/display-pixel-ratio.js b/devtools/client/responsive.html/reducers/display-pixel-ratio.js deleted file mode 100644 index dd1a9ae715d0..000000000000 --- a/devtools/client/responsive.html/reducers/display-pixel-ratio.js +++ /dev/null @@ -1,26 +0,0 @@ -/* 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/. */ - -/* eslint-env browser */ - -"use strict"; - -const { CHANGE_DISPLAY_PIXEL_RATIO } = require("../actions/index"); -const INITIAL_DISPLAY_PIXEL_RATIO = 0; - -const reducers = { - - [CHANGE_DISPLAY_PIXEL_RATIO](_, action) { - return action.displayPixelRatio; - }, - -}; - -module.exports = function(displayPixelRatio = INITIAL_DISPLAY_PIXEL_RATIO, action) { - const reducer = reducers[action.type]; - if (!reducer) { - return displayPixelRatio; - } - return reducer(displayPixelRatio, action); -}; diff --git a/devtools/client/responsive.html/reducers/location.js b/devtools/client/responsive.html/reducers/location.js deleted file mode 100644 index 02ccfdf08d81..000000000000 --- a/devtools/client/responsive.html/reducers/location.js +++ /dev/null @@ -1,25 +0,0 @@ -/* 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 { CHANGE_LOCATION } = require("../actions/index"); - -const INITIAL_LOCATION = "about:blank"; - -const reducers = { - - [CHANGE_LOCATION](_, action) { - return action.location; - }, - -}; - -module.exports = function(location = INITIAL_LOCATION, action) { - const reducer = reducers[action.type]; - if (!reducer) { - return location; - } - return reducer(location, action); -}; diff --git a/devtools/client/responsive.html/reducers/moz.build b/devtools/client/responsive.html/reducers/moz.build index f7d191b6dadc..3f2f60d74c1b 100644 --- a/devtools/client/responsive.html/reducers/moz.build +++ b/devtools/client/responsive.html/reducers/moz.build @@ -6,11 +6,8 @@ DevToolsModules( 'devices.js', - 'display-pixel-ratio.js', - 'location.js', 'reload-conditions.js', 'screenshot.js', - 'touch-simulation.js', 'ui.js', 'viewports.js', ) diff --git a/devtools/client/responsive.html/reducers/screenshot.js b/devtools/client/responsive.html/reducers/screenshot.js index 11246f5bddac..e26380889d58 100644 --- a/devtools/client/responsive.html/reducers/screenshot.js +++ b/devtools/client/responsive.html/reducers/screenshot.js @@ -9,7 +9,9 @@ const { TAKE_SCREENSHOT_START, } = require("../actions/index"); -const INITIAL_SCREENSHOT = { isCapturing: false }; +const INITIAL_SCREENSHOT = { + isCapturing: false, +}; const reducers = { diff --git a/devtools/client/responsive.html/reducers/touch-simulation.js b/devtools/client/responsive.html/reducers/touch-simulation.js deleted file mode 100644 index 6aebaa40d914..000000000000 --- a/devtools/client/responsive.html/reducers/touch-simulation.js +++ /dev/null @@ -1,31 +0,0 @@ -/* 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 { - CHANGE_TOUCH_SIMULATION, -} = require("../actions/index"); - -const INITIAL_TOUCH_SIMULATION = { - enabled: false, -}; - -const reducers = { - - [CHANGE_TOUCH_SIMULATION](touchSimulation, { enabled }) { - return Object.assign({}, touchSimulation, { - enabled, - }); - }, - -}; - -module.exports = function(touchSimulation = INITIAL_TOUCH_SIMULATION, action) { - const reducer = reducers[action.type]; - if (!reducer) { - return touchSimulation; - } - return reducer(touchSimulation, action); -}; diff --git a/devtools/client/responsive.html/reducers/ui.js b/devtools/client/responsive.html/reducers/ui.js index 10e93e10f645..5f3c8f27ddb0 100644 --- a/devtools/client/responsive.html/reducers/ui.js +++ b/devtools/client/responsive.html/reducers/ui.js @@ -7,18 +7,30 @@ const Services = require("Services"); const { + CHANGE_DISPLAY_PIXEL_RATIO, TOGGLE_LEFT_ALIGNMENT, + TOGGLE_TOUCH_SIMULATION, } = require("../actions/index"); const LEFT_ALIGNMENT_ENABLED = "devtools.responsive.leftAlignViewport.enabled"; const INITIAL_UI = { + // The pixel ratio of the display. + displayPixelRatio: 0, // Whether or not the viewports are left aligned. leftAlignmentEnabled: Services.prefs.getBoolPref(LEFT_ALIGNMENT_ENABLED), + // Whether or not touch simulation is enabled. + touchSimulationEnabled: false, }; const reducers = { + [CHANGE_DISPLAY_PIXEL_RATIO](ui, { displayPixelRatio }) { + return Object.assign({}, ui, { + displayPixelRatio, + }); + }, + [TOGGLE_LEFT_ALIGNMENT](ui, { enabled }) { const leftAlignmentEnabled = enabled !== undefined ? enabled : !ui.leftAlignmentEnabled; @@ -30,6 +42,12 @@ const reducers = { }); }, + [TOGGLE_TOUCH_SIMULATION](ui, { enabled }) { + return Object.assign({}, ui, { + touchSimulationEnabled: enabled, + }); + }, + }; module.exports = function(ui = INITIAL_UI, action) { diff --git a/devtools/client/responsive.html/reducers/viewports.js b/devtools/client/responsive.html/reducers/viewports.js index 507b5610b0d3..f75ac146a28a 100644 --- a/devtools/client/responsive.html/reducers/viewports.js +++ b/devtools/client/responsive.html/reducers/viewports.js @@ -22,9 +22,7 @@ const INITIAL_VIEWPORT = { deviceType: "", width: 320, height: 480, - pixelRatio: { - value: 0, - }, + pixelRatio: 0, userContextId: 0, }; @@ -60,9 +58,7 @@ const reducers = { } return Object.assign({}, viewport, { - pixelRatio: { - value: pixelRatio - }, + pixelRatio, }); }); }, diff --git a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js index 5289ebe3a156..7e1760f163ab 100644 --- a/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js +++ b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js @@ -5,18 +5,18 @@ // Test changing the display pixel ratio. -const { changeDisplayPixelRatio } = - require("devtools/client/responsive.html/actions/display-pixel-ratio"); +const { changeDisplayPixelRatio } = require("devtools/client/responsive.html/actions/ui"); + const NEW_PIXEL_RATIO = 5.5; add_task(async function() { const store = Store(); const { getState, dispatch } = store; - equal(getState().displayPixelRatio, 0, + equal(getState().ui.displayPixelRatio, 0, "Defaults to 0 at startup"); dispatch(changeDisplayPixelRatio(NEW_PIXEL_RATIO)); - equal(getState().displayPixelRatio, NEW_PIXEL_RATIO, + equal(getState().ui.displayPixelRatio, NEW_PIXEL_RATIO, `Display Pixel Ratio changed to ${NEW_PIXEL_RATIO}`); }); diff --git a/devtools/client/responsive.html/test/unit/test_change_location.js b/devtools/client/responsive.html/test/unit/test_change_location.js deleted file mode 100644 index f8d3274550c0..000000000000 --- a/devtools/client/responsive.html/test/unit/test_change_location.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -// Test changing the location of the displayed page. - -const { changeLocation } = - require("devtools/client/responsive.html/actions/location"); - -const TEST_URL = "http://example.com"; - -add_task(async function() { - const store = Store(); - const { getState, dispatch } = store; - - equal(getState().location, "about:blank", - "Defaults to about:blank at startup"); - - dispatch(changeLocation(TEST_URL)); - equal(getState().location, TEST_URL, "Location changed to TEST_URL"); -}); diff --git a/devtools/client/responsive.html/test/unit/test_change_pixel_ratio.js b/devtools/client/responsive.html/test/unit/test_change_pixel_ratio.js index c3df945c9521..4cfe5e772a66 100644 --- a/devtools/client/responsive.html/test/unit/test_change_pixel_ratio.js +++ b/devtools/client/responsive.html/test/unit/test_change_pixel_ratio.js @@ -17,6 +17,6 @@ add_task(async function() { dispatch(changePixelRatio(0, NEW_PIXEL_RATIO)); const viewport = getState().viewports[0]; - equal(viewport.pixelRatio.value, NEW_PIXEL_RATIO, + equal(viewport.pixelRatio, NEW_PIXEL_RATIO, `Viewport's pixel ratio changed to ${NEW_PIXEL_RATIO}`); }); diff --git a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js index 12ab4e2bcf61..a18107ed4bf1 100644 --- a/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js +++ b/devtools/client/responsive.html/test/unit/test_update_touch_simulation_enabled.js @@ -5,19 +5,17 @@ // Test updating the touch simulation `enabled` property -const { - changeTouchSimulation, -} = require("devtools/client/responsive.html/actions/touch-simulation"); +const { toggleTouchSimulation } = require("devtools/client/responsive.html/actions/ui"); add_task(async function() { const store = Store(); const { getState, dispatch } = store; - ok(!getState().touchSimulation.enabled, + ok(!getState().ui.touchSimulationEnabled, "Touch simulation is disabled by default."); - dispatch(changeTouchSimulation(true)); + dispatch(toggleTouchSimulation(true)); - ok(getState().touchSimulation.enabled, + ok(getState().ui.touchSimulationEnabled, "Touch simulation is enabled."); }); diff --git a/devtools/client/responsive.html/test/unit/xpcshell.ini b/devtools/client/responsive.html/test/unit/xpcshell.ini index 432e68ed2030..b5241660f4c0 100644 --- a/devtools/client/responsive.html/test/unit/xpcshell.ini +++ b/devtools/client/responsive.html/test/unit/xpcshell.ini @@ -8,7 +8,6 @@ firefox-appdir = browser [test_add_viewport.js] [test_change_device.js] [test_change_display_pixel_ratio.js] -[test_change_location.js] [test_change_network_throttling.js] [test_change_pixel_ratio.js] [test_resize_viewport.js] diff --git a/devtools/client/responsive.html/types.js b/devtools/client/responsive.html/types.js index 99d89cae6a9e..3130550a58e8 100644 --- a/devtools/client/responsive.html/types.js +++ b/devtools/client/responsive.html/types.js @@ -24,11 +24,6 @@ exports.loadableState = createEnum([ /* GLOBAL */ -/** - * The location of the document displayed in the viewport(s). - */ -exports.location = PropTypes.string; - /** * Whether to reload the page automatically when certain actions occur. */ @@ -130,16 +125,6 @@ exports.networkThrottling = { }; -/** - * Device pixel ratio for a given viewport. - */ -const pixelRatio = exports.pixelRatio = { - - // The device pixel ratio value - value: PropTypes.number, - -}; - /** * Touch simulation state for a given viewport. */ @@ -171,7 +156,7 @@ exports.viewport = { height: PropTypes.number, // The device pixel ratio of the viewport - pixelRatio: PropTypes.shape(pixelRatio), + pixelRatio: PropTypes.number, // The user context (container) ID for the viewport // Defaults to 0 meaning the default context From 6aa393fdeec7482e61e12532ae590cb655bfd969 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Tue, 4 Sep 2018 13:40:42 -0400 Subject: [PATCH 62/80] Bug 1488450 - Enable the flexbox inspector for browser_markup_flex_display_badge.js to prevent perma-failure in beta mochitests. r=jdescottes --- .../inspector/markup/test/browser_markup_flex_display_badge.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devtools/client/inspector/markup/test/browser_markup_flex_display_badge.js b/devtools/client/inspector/markup/test/browser_markup_flex_display_badge.js index 68f44fbd041b..709df6a53c74 100644 --- a/devtools/client/inspector/markup/test/browser_markup_flex_display_badge.js +++ b/devtools/client/inspector/markup/test/browser_markup_flex_display_badge.js @@ -17,6 +17,8 @@ const TEST_URI = ` const HIGHLIGHTER_TYPE = "FlexboxHighlighter"; add_task(async function() { + await pushPref("devtools.inspector.flexboxHighlighter.enabled", true); + await pushPref("devtools.flexboxinspector.enabled", true); await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); const { inspector } = await openLayoutView(); const { highlighters, store } = inspector; From d50cb5e5d825d1dd59dc9d3112344490999025b7 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 4 Sep 2018 13:58:27 -0400 Subject: [PATCH 63/80] Bug 1485155 - 1. Fix javadoc warnings; r=jchen Differential Revision: https://phabricator.services.mozilla.com/D3924 --- .../geckoview/GeckoRuntimeSettings.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java index c1c194b27af9..884e4bd17301 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java @@ -251,8 +251,8 @@ public final class GeckoRuntimeSettings implements Parcelable { /** Set whether or not known malware sites should be blocked. * - * Note: For each blocked site, {@link NavigationDelegate#onLoadError} - * with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} + * Note: For each blocked site, {@link GeckoSession.NavigationDelegate#onLoadError} + * with error category {@link GeckoSession.NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} * is called. * * @param enabled A flag determining whether or not to block malware @@ -267,8 +267,8 @@ public final class GeckoRuntimeSettings implements Parcelable { /** * Set whether or not known phishing sites should be blocked. * - * Note: For each blocked site, {@link NavigationDelegate#onLoadError} - * with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} + * Note: For each blocked site, {@link GeckoSession.NavigationDelegate#onLoadError} + * with error category {@link GeckoSession.NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} * is called. * * @param enabled A flag determining whether or not to block phishing @@ -532,7 +532,9 @@ public final class GeckoRuntimeSettings implements Parcelable { } /** - * Get the Job Id used on Oreo and later devices to manage crash reporting in background. + * Get the Job ID used on Oreo and later devices to manage crash reporting in background. + * + * @return Crash reporting service Job ID */ public int getCrashReportingServiceJobId() { return mCrashReportingJobId; @@ -724,8 +726,8 @@ public final class GeckoRuntimeSettings implements Parcelable { /** * Set whether or not known malware sites should be blocked. * - * Note: For each blocked site, {@link NavigationDelegate#onLoadError} - * with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} + * Note: For each blocked site, {@link GeckoSession.NavigationDelegate#onLoadError} + * with error category {@link GeckoSession.NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} * is called. * * @param enabled A flag determining whether or not to block malware sites. @@ -748,8 +750,8 @@ public final class GeckoRuntimeSettings implements Parcelable { /** * Set whether or not known phishing sites should be blocked. * - * Note: For each blocked site, {@link NavigationDelegate#onLoadError} - * with error category {@link NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} + * Note: For each blocked site, {@link GeckoSession.NavigationDelegate#onLoadError} + * with error category {@link GeckoSession.NavigationDelegate#ERROR_CATEGORY_SAFEBROWSING} * is called. * * @param enabled A flag determining whether or not to block phishing sites. From 9ffc2ddc01c586bf02b83989336996ef6ad18dee Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 4 Sep 2018 13:58:27 -0400 Subject: [PATCH 64/80] Bug 1485155 - 2. Treat javadoc warnings as errors; r=nalexander Some common javadoc mistakes are logged as warnings and are being overlooked. javadoc does not support warning-as-error natively, so this patch scans the javadoc output in gradle and makes the task fail if any warnings are detected. Differential Revision: https://phabricator.services.mozilla.com/D3925 --- mobile/android/geckoview/build.gradle | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/mobile/android/geckoview/build.gradle b/mobile/android/geckoview/build.gradle index 30f1f070e624..b2bf0d2ad6fe 100644 --- a/mobile/android/geckoview/build.gradle +++ b/mobile/android/geckoview/build.gradle @@ -190,6 +190,26 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) { } } +tasks.withType(Javadoc) { + // Implement warning-as-error for javadoc. + def warnings = 0 + def listener = { + if (it.contains(': warning')) { + warnings++ + } + } as StandardOutputListener + + doFirst { + logging.addStandardErrorListener(listener) + } + doLast { + logging.removeStandardErrorListener(listener) + if (warnings > 0) { + throw new GradleException("Treating $warnings javadoc warning(s) as error(s)") + } + } +} + dependencies { implementation "com.android.support:support-v4:$support_library_version" implementation "com.android.support:palette-v7:$support_library_version" From 031bc0c26211d83fe70df9d3a11a2ae5424bed43 Mon Sep 17 00:00:00 2001 From: Gurzau Raul Date: Tue, 4 Sep 2018 21:18:53 +0300 Subject: [PATCH 65/80] Backed out changeset f7d509458e63 (bug 1487295) for failing at PaymentMethodChangeEvent/methodDetails-attribute.https.html on a CLOSED TREE --- dom/payments/PaymentMethodChangeEvent.cpp | 4 +++- dom/payments/PaymentMethodChangeEvent.h | 1 - dom/webidl/PaymentMethodChangeEvent.webidl | 4 ++-- testing/web-platform/meta/MANIFEST.json | 4 ++-- .../methodDetails-attribute.https.html | 11 ----------- .../methodName-attribute.https.html | 11 ----------- 6 files changed, 7 insertions(+), 28 deletions(-) diff --git a/dom/payments/PaymentMethodChangeEvent.cpp b/dom/payments/PaymentMethodChangeEvent.cpp index 8ce0b1473fa4..c2030469d70a 100644 --- a/dom/payments/PaymentMethodChangeEvent.cpp +++ b/dom/payments/PaymentMethodChangeEvent.cpp @@ -72,7 +72,9 @@ PaymentMethodChangeEvent::init( const PaymentMethodChangeEventInit& aEventInitDict) { mMethodName.Assign(aEventInitDict.mMethodName); - mMethodDetails = aEventInitDict.mMethodDetails; + if (aEventInitDict.mMethodDetails.WasPassed()) { + mMethodDetails = aEventInitDict.mMethodDetails.Value(); + } } void diff --git a/dom/payments/PaymentMethodChangeEvent.h b/dom/payments/PaymentMethodChangeEvent.h index 9518825e2821..a7a07eb36397 100644 --- a/dom/payments/PaymentMethodChangeEvent.h +++ b/dom/payments/PaymentMethodChangeEvent.h @@ -14,7 +14,6 @@ namespace mozilla { namespace dom { class PaymentRequestUpdateEvent; -struct PaymentMethodChangeEventInit; class PaymentMethodChangeEvent final : public PaymentRequestUpdateEvent { public: diff --git a/dom/webidl/PaymentMethodChangeEvent.webidl b/dom/webidl/PaymentMethodChangeEvent.webidl index 0d80dbf49900..551e6042141d 100644 --- a/dom/webidl/PaymentMethodChangeEvent.webidl +++ b/dom/webidl/PaymentMethodChangeEvent.webidl @@ -8,6 +8,6 @@ interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent { }; dictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit { - DOMString methodName = ""; - object? methodDetails = null; + required DOMString methodName; + object? methodDetails; }; diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 1be9c8dc4fb8..20935804299d 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -620617,11 +620617,11 @@ "testharness" ], "payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html": [ - "ec0aa96dddb46b26617064ab54e9d02e2a588cbb", + "a478c559d497e8dea9d471ce1e36427bfb741aa7", "testharness" ], "payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html": [ - "176638c7852f6f0f8fd7a8c3dfefdf439a829d22", + "e6e0bf9a91971b3a20acf59cf27097281f0d2085", "testharness" ], "payment-request/PaymentRequestUpdateEvent/constructor.http.html": [ diff --git a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html index ec0aa96dddb4..a478c559d497 100644 --- a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html +++ b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodDetails-attribute.https.html @@ -19,15 +19,4 @@ test(() => { assert_equals(test, "pass"); assert_equals(event.methodDetails, methodDetails); }, "Must have a methodDetails IDL attribute, which is initialized with to the methodName dictionary value"); - -test(() => { - const event = new PaymentMethodChangeEvent("test"); - assert_equals(event.methodDetails, null, "methodDetails attribute must initialize to null"); - - const event2 = new PaymentMethodChangeEvent("test", { methodName: "basic-card" }); - assert_equals(event2.methodDetails, null, "methodDetails attribute must initialize to null"); - - const event3 = new PaymentMethodChangeEvent("test", {}); - assert_equals(event2.methodDetails, null, "methodDetails attribute must initialize to null"); -}, "The methodDetails member defaults to null"); diff --git a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html index 176638c7852f..e6e0bf9a9197 100644 --- a/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html +++ b/testing/web-platform/tests/payment-request/PaymentMethodChangeEvent/methodName-attribute.https.html @@ -14,15 +14,4 @@ test(() => { const { methodName } = event; assert_equals(methodName, "wpt-test"); }, "Must have a methodName IDL attribute, which is initialized with to the methodName dictionary value"); - -test(() => { - const event = new PaymentMethodChangeEvent("test"); - assert_equals(event.methodName, "", "methodName attribute must initialize to empty string"); - - const event2 = new PaymentMethodChangeEvent("test", { methodDetails: {} }); - assert_equals(event2.methodName, "", "methodName attribute must initialize to empty string"); - - const event3 = new PaymentMethodChangeEvent("test", {}); - assert_equals(event3.methodName, "", "methodName attribute must initialize to empty string"); -}, "When no dictionary is passed, the methodName member defaults to the empty string"); From 5b6ff91365b0ac9b6044cb54e700ab24c840ef3c Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 4 Sep 2018 10:15:00 -0400 Subject: [PATCH 66/80] Bug 1488436 - Remove the duplicated 'Change block list' link in the Content Blocking section of Preferences; r=johannh Differential Revision: https://phabricator.services.mozilla.com/D4940 --- browser/components/preferences/in-content/privacy.xul | 1 - 1 file changed, 1 deletion(-) diff --git a/browser/components/preferences/in-content/privacy.xul b/browser/components/preferences/in-content/privacy.xul index 3db43e9f5eb9..bd3cb49bd759 100644 --- a/browser/components/preferences/in-content/privacy.xul +++ b/browser/components/preferences/in-content/privacy.xul @@ -370,7 +370,6 @@ data-l10n-id="content-blocking-tracking-protection-option-always" flex="1" /> -