author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Wed, 30 Dec 2015 12:15:55 +0100 | |
changeset 277885 | b493cf33851fc44f9fef8179bc88969f10df3ff6 |
parent 277831 | f916b88c87b50619d9b05599f5d2581b84f6d557 (current diff) |
parent 277884 | c690c50b2b543b420803e8192d6e08e06b20e0a3 (diff) |
child 277886 | ee4446a2c02a04f6fba9c6ba573ab45445997277 |
push id | 69628 |
push user | cbook@mozilla.com |
push date | Wed, 30 Dec 2015 11:16:09 +0000 |
treeherder | mozilla-inbound@b493cf33851f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 46.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> @@ -134,17 +134,17 @@ <!-- Platform common things --> <project name="device-shinano-common" path="device/sony/shinano-common" remote="b2g" revision="03f7deda712e213aabf79eb657bd902497e3b201"/> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/> <project name="device/qcom/common" path="device/qcom/common" revision="2501e5940ba69ece7654ff85611c76ae5bda299c"/> <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="da1273d39b3b940b3b2a5bc5fdb81c521d74caa3"/> <project name="init_sh" path="external/init_sh" remote="b2g" revision="feb58d2b397e45ead9b904d5c4d9255df408db56"/> <project name="platform_bionic" path="bionic" remote="b2g" revision="3e85c4683c121530c1c3a48c696a569bf5f587e2"/> <project name="platform_external_bluetooth_bluedroid" path="external/bluetooth/bluedroid" remote="b2g" revision="70f536bd97d901b96b94669ae1aa2fd0fb54b258"/> - <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="b2g" revision="2d017f975f4542c6d23b226ec172b9b30383c31c"/> + <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="b2g" revision="2a52bd77d2ca0cefbf02acc6863492d16b6ccfec"/> <project name="platform_external_libnfc-pn547" path="external/libnfc-pn547" remote="b2g" revision="5bb999b84b8adc14f6bea004d523ba258dea8188"/> <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/> <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="5d5bcc83d6c32874701f0df78ed1119e006bd10a"/> <project name="platform/frameworks/base" path="frameworks/base" revision="da8e6bc53c8bc669da0bb627904d08aa293f2497"/> <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/> <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/> <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="15a9b66de9b7d84c7ea63df3a834f095bca9e493"/> <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="8d7676dfb68ee0cd069affedd5d1e97316a184ba"/>
--- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk-specific things and forks --> <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/> <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c"> <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk-specific things and forks --> <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/> <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c"> <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23", + "git_revision": "1899109c9fd9b9e2244155c4b9e966c0a48368fc", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "9cfeee1568995b5cf0f58db8924baff387871876", + "revision": "cfb223aa835d5bf17ec0fd03f873b6788a149edb", "repo_path": "integration/gaia-central" }
--- a/b2g/config/nexus-4-kk/sources.xml +++ b/b2g/config/nexus-4-kk/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -16,17 +16,17 @@ <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/> <!--original fetch url was git://github.com/mozilla/--> <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G repositories for all targets --> - <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/> <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/> <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -643,19 +643,19 @@ @RESPATH@/components/XULStore.manifest @RESPATH@/components/Webapps.js @RESPATH@/components/Webapps.manifest @RESPATH@/components/AppsService.js @RESPATH@/components/AppsService.manifest @RESPATH@/components/Push.js @RESPATH@/components/Push.manifest #ifdef MOZ_SIMPLEPUSH -@RESPATH@/components/PushComponents.js +@RESPATH@/components/PushServiceLauncher.js #else -@RESPATH@/components/PushServiceLauncher.js +@RESPATH@/components/PushComponents.js #endif @RESPATH@/components/InterAppComm.manifest @RESPATH@/components/InterAppCommService.js @RESPATH@/components/InterAppConnection.js @RESPATH@/components/InterAppMessagePort.js @RESPATH@/components/nsDOMIdentity.js
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1606,23 +1606,16 @@ pref("dom.ipc.reportProcessHangs", true) pref("browser.reader.detectedFirstArticle", false); // Don't limit how many nodes we care about on desktop: pref("reader.parse-node-limit", 0); // On desktop, we want the URLs to be included here for ease of debugging, // and because (normally) these errors are not persisted anywhere. pref("reader.errors.includeURLs", true); -pref("browser.pocket.enabled", true); -pref("browser.pocket.api", "api.getpocket.com"); -pref("browser.pocket.site", "getpocket.com"); -pref("browser.pocket.oAuthConsumerKey", "40249-e88c401e1b1f2242d9e441c4"); -pref("browser.pocket.useLocaleList", true); -pref("browser.pocket.enabledLocales", "cs de en-GB en-US en-ZA es-ES es-MX fr hu it ja ja-JP-mac ko nl pl pt-BR pt-PT ru zh-CN zh-TW"); - pref("view_source.tab", true); pref("dom.serviceWorkers.enabled", true); pref("dom.serviceWorkers.interception.enabled", true); pref("dom.serviceWorkers.openWindow.enabled", true); #ifndef RELEASE_BUILD // Enable Push API.
--- a/browser/base/content/browser-context.inc +++ b/browser/base/content/browser-context.inc @@ -74,20 +74,16 @@ <menuitem id="context-sharelink" label="&shareLink.label;" accesskey="&shareLink.accesskey;" oncommand="gContextMenu.shareLink();"/> <menuitem id="context-savelink" label="&saveLinkCmd.label;" accesskey="&saveLinkCmd.accesskey;" oncommand="gContextMenu.saveLink();"/> - <menuitem id="context-savelinktopocket" - label="&saveLinkToPocketCmd.label;" - accesskey="&saveLinkToPocketCmd.accesskey;" - oncommand="gContextMenu.saveLinkToPocket();"/> <menu id="context-marklinkMenu" label="&social.marklinkMenu.label;" accesskey="&social.marklinkMenu.accesskey;"> <menupopup/> </menu> <menuitem id="context-copyemail" label="©EmailCmd.label;" accesskey="©EmailCmd.accesskey;" oncommand="gContextMenu.copyEmail();"/> @@ -265,20 +261,16 @@ <menuitem id="context-sharepage" label="&sharePageCmd.label;" accesskey="&sharePageCmd.accesskey;" oncommand="SocialShare.sharePage();"/> <menuitem id="context-savepage" label="&savePageCmd.label;" accesskey="&savePageCmd.accesskey2;" oncommand="gContextMenu.savePageAs();"/> - <menuitem id="context-pocket" - label="&saveToPocketCmd.label;" - accesskey="&saveToPocketCmd.accesskey;" - oncommand="gContextMenu.savePageToPocket();"/> <menu id="context-markpageMenu" label="&social.markpageMenu.label;" accesskey="&social.markpageMenu.accesskey;"> <menupopup/> </menu> <menuseparator id="context-sep-viewbgimage"/> <menuitem id="context-viewbgimage" label="&viewBGImageCmd.label;" accesskey="&viewBGImageCmd.accesskey;"
--- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -408,31 +408,24 @@ #ifndef XP_MACOSX placespopup="true" #endif context="placesContext" openInTabs="children" oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);" onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);" onpopupshowing="BookmarkingUI.onMainMenuPopupShowing(event); - BookmarkingUI.updatePocketItemVisibility('menu_'); if (!this.parentNode._placesView) new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');" tooltip="bhTooltip" popupsinherittooltip="true"> <menuitem id="bookmarksShowAll" label="&showAllBookmarks2.label;" command="Browser:ShowAllBookmarks" key="manBookmarkKb"/> <menuseparator id="organizeBookmarksSeparator"/> - <menuitem id="menu_pocket" label="&pocketMenuitem.label;" -#ifndef XP_MACOSX - class="menuitem-iconic" -#endif - oncommand="openUILink(Pocket.listURL, event);"/> - <menuseparator id="menu_pocketSeparator"/> <menuitem id="menu_bookmarkThisPage" command="Browser:AddBookmarkAs" observes="bookmarkThisPageBroadcaster" key="addBookmarkAsKb"/> <menuitem id="subscribeToPageMenuitem" #ifndef XP_MACOSX class="menuitem-iconic" #endif
--- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -1549,22 +1549,16 @@ var BookmarkingUI = { } }, onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) { this._updateBookmarkPageMenuItem(); PlacesCommandHook.updateBookmarkAllTabsCommand(); }, - updatePocketItemVisibility: function BUI_updatePocketItemVisibility(prefix) { - let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button"); - document.getElementById(prefix + "pocket").hidden = hidden; - document.getElementById(prefix + "pocketSeparator").hidden = hidden; - }, - _showBookmarkedNotification: function BUI_showBookmarkedNotification() { function getCenteringTransformForRects(rectToPosition, referenceRect) { let topDiff = referenceRect.top - rectToPosition.top; let leftDiff = referenceRect.left - rectToPosition.left; let heightDiff = referenceRect.height - rectToPosition.height; let widthDiff = referenceRect.width - rectToPosition.width; return [(leftDiff + .5 * widthDiff) + "px", (topDiff + .5 * heightDiff) + "px"]; } @@ -1676,17 +1670,16 @@ var BookmarkingUI = { case "ViewHiding": this.onPanelMenuViewHiding(aEvent); break; } }, onPanelMenuViewShowing: function BUI_onViewShowing(aEvent) { this._updateBookmarkPageMenuItem(); - this.updatePocketItemVisibility("panelMenu_"); // Update checked status of the toolbar toggle. let viewToolbar = document.getElementById("panelMenu_viewBookmarksToolbar"); let personalToolbar = document.getElementById("PersonalToolbar"); if (personalToolbar.collapsed) viewToolbar.removeAttribute("checked"); else viewToolbar.setAttribute("checked", "true"); // Get all statically placed buttons to supply them with keyboard shortcuts.
--- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -1343,19 +1343,18 @@ SocialMarks = { } }, getProviders: function() { // only rely on providers that the user has placed in the UI somewhere. This // also means that populateToolbarPalette must be called prior to using this // method, otherwise you get a big fat zero. For our use case with context // menu's, this is ok. - let tbh = this._toolbarHelper; return [p for (p of Social.providers) if (p.markURL && - document.getElementById(tbh.idFromOrigin(p.origin)))]; + document.getElementById(this._toolbarHelper.idFromOrigin(p.origin)))]; }, populateContextMenu: function() { // only show a selection if enabled and there is more than one let providers = this.getProviders(); // remove all previous entries by class let menus = [m for (m of document.getElementsByClassName("context-socialmarks"))];
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -48,47 +48,16 @@ XPCOMUtils.defineLazyServiceGetter(this, "mozIAsyncFavicons"); XPCOMUtils.defineLazyServiceGetter(this, "gDNSService", "@mozilla.org/network/dns-service;1", "nsIDNSService"); XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils", "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Pocket", - "resource:///modules/Pocket.jsm"); - -// Can't use XPCOMUtils for these because the scripts try to define the variables -// on window, and so the defineProperty inside defineLazyGetter fails. -Object.defineProperty(window, "pktApi", { - get: function() { - // Avoid this getter running again: - delete window.pktApi; - Services.scriptloader.loadSubScript("chrome://browser/content/pocket/pktApi.js", window); - return window.pktApi; - }, - configurable: true, - enumerable: true -}); - -function pktUIGetter(prop) { - return { - get: function() { - // Avoid either of these getters running again: - delete window.pktUI; - delete window.pktUIMessaging; - Services.scriptloader.loadSubScript("chrome://browser/content/pocket/main.js", window); - return window[prop]; - }, - configurable: true, - enumerable: true - }; -} -Object.defineProperty(window, "pktUI", pktUIGetter("pktUI")); -Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging")); XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() { return Services.strings.createBundle('chrome://browser/locale/browser.properties'); }); const nsIWebNavigation = Ci.nsIWebNavigation; var gLastBrowserCharset = null; @@ -7092,16 +7061,19 @@ var gIdentityHandler = { host = this.getEffectiveHost(); } catch (e) { // Some URIs might have no hosts. } // Fallback for special protocols. if (!host) { host = this._uri.specIgnoringRef; + // Special URIs without a host (eg, about:) should crop the end so + // the protocol can be seen. + crop = "end"; } // Fill in the CA name if we have a valid TLS certificate. if (this._isSecure) { verifier = this._identityBox.tooltipText; } // Fill in organization information if we have a valid EV certificate.
--- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -615,19 +615,19 @@ to the default placements of buttons in CustomizableUI.jsm, so the customization code doesn't get confused. --> <toolbar id="nav-bar" aria-label="&navbarCmd.label;" fullscreentoolbar="true" mode="icons" customizable="true" iconsize="small" #ifdef MOZ_DEV_EDITION - defaultset="urlbar-container,search-container,developer-button,bookmarks-menu-button,pocket-button,downloads-button,home-button,loop-button" + defaultset="urlbar-container,search-container,developer-button,bookmarks-menu-button,downloads-button,home-button,loop-button" #else - defaultset="urlbar-container,search-container,bookmarks-menu-button,pocket-button,downloads-button,home-button,loop-button" + defaultset="urlbar-container,search-container,bookmarks-menu-button,downloads-button,home-button,loop-button" #endif customizationtarget="nav-bar-customization-target" overflowable="true" overflowbutton="nav-bar-overflow-button" overflowtarget="widget-overflow-list" overflowpanel="widget-overflow" context="toolbar-context-menu"> @@ -793,38 +793,32 @@ <menupopup id="BMB_bookmarksPopup" class="cui-widget-panel cui-widget-panelview cui-widget-panelWithFooter PanelUI-subView" placespopup="true" context="placesContext" openInTabs="children" oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);" onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);" onpopupshowing="BookmarkingUI.onPopupShowing(event); - BookmarkingUI.updatePocketItemVisibility('BMB_'); BookmarkingUI.attachPlacesView(event, this);" tooltip="bhTooltip" popupsinherittooltip="true"> <menuitem id="BMB_viewBookmarksSidebar" class="subviewbutton" label="&viewBookmarksSidebar2.label;" type="checkbox" oncommand="SidebarUI.toggle('viewBookmarksSidebar');"> <observes element="viewBookmarksSidebar" attribute="checked"/> </menuitem> <!-- NB: temporary solution for bug 985024, this should go away soon. --> <menuitem id="BMB_bookmarksShowAllTop" class="menuitem-iconic subviewbutton" label="&showAllBookmarks2.label;" command="Browser:ShowAllBookmarks" key="manBookmarkKb"/> <menuseparator/> - <menuitem id="BMB_pocket" - class="menuitem-iconic bookmark-item subviewbutton" - label="&pocketMenuitem.label;" - oncommand="openUILink(Pocket.listURL, event);"/> - <menuseparator id="BMB_pocketSeparator"/> <menuitem id="BMB_subscribeToPageMenuitem" #ifndef XP_MACOSX class="menuitem-iconic subviewbutton" #else class="subviewbutton" #endif label="&subscribeToPageMenuitem.label;" oncommand="return FeedHandler.subscribeToFeed(null, event);"
--- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -6,20 +6,16 @@ Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm"); Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm"); Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", - "resource:///modules/CustomizableUI.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Pocket", - "resource:///modules/Pocket.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper", "resource://gre/modules/LoginHelper.jsm"); var gContextMenuContentData = null; function nsContextMenu(aXulMenu, aIsShift) { this.shouldDisplay = true; this.initMenu(aXulMenu, aIsShift); @@ -211,35 +207,16 @@ nsContextMenu.prototype = { // SimpleServiceDiscovery.services), but SimpleServiceDiscovery is guaranteed // to be already loaded, since we load it on startup in nsBrowserGlue, // and CastingApps isn't, so check SimpleServiceDiscovery.services first // to avoid needing to load CastingApps.jsm if we don't need to. shouldShowCast = shouldShowCast && this.mediaURL && SimpleServiceDiscovery.services.length > 0 && CastingApps.getServicesForVideo(this.target).length > 0; this.setItemAttr("context-castvideo", "disabled", !shouldShowCast); - - this.initPocketItems(); - }, - - initPocketItems: function CM_initPocketItems() { - var showSaveCurrentPageToPocket = !(this.onTextInput || this.onLink || - this.isContentSelected || this.onImage || - this.onCanvas || this.onVideo || this.onAudio); - let targetURI = (this.onSaveableLink || this.onPlainTextLink) ? this.linkURI : this.browser.currentURI; - let canPocket = CustomizableUI.getPlacementOfWidget("pocket-button") && - window.pktApi && window.pktApi.isUserLoggedIn(); - canPocket = canPocket && (targetURI.schemeIs("http") || targetURI.schemeIs("https") || - (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetURI.spec))); - canPocket = canPocket && window.gBrowser && this.browser.getTabBrowser() == window.gBrowser; - - this.showItem("context-pocket", canPocket && showSaveCurrentPageToPocket); - let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket && - (this.onSaveableLink || this.onPlainTextLink); - this.showItem("context-savelinktopocket", showSaveLinkToPocket); }, initViewItems: function CM_initViewItems() { // View source is always OK, unless in directory listing. this.showItem("context-viewpartialsource-selection", this.isContentSelected); this.showItem("context-viewpartialsource-mathml", this.onMathML && !this.isContentSelected); @@ -1716,24 +1693,16 @@ nsContextMenu.prototype = { shareSelect: function CM_shareSelect() { SocialShare.sharePage(null, { url: this.browser.currentURI.spec, text: this.textSelected }, this.target); }, savePageAs: function CM_savePageAs() { saveBrowser(this.browser); }, - saveLinkToPocket: function CM_saveLinkToPocket() { - Pocket.savePage(this.browser, this.linkURL); - }, - - savePageToPocket: function CM_saveToPocket() { - Pocket.savePage(this.browser, this.browser.currentURI.spec, this.browser.contentTitle); - }, - printFrame: function CM_printFrame() { PrintUtils.printWindow(this.frameOuterWindowID, this.browser); }, switchPageDirection: function CM_switchPageDirection() { this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection"); },
--- a/browser/base/content/test/social/browser_addons.js +++ b/browser/base/content/test/social/browser_addons.js @@ -7,25 +7,25 @@ var manifest = { sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html", iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png" }; var manifest2 = { // used for testing install name: "provider 2", origin: "https://test1.example.com", sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar_empty.html", iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; var manifestUpgrade = { // used for testing install name: "provider 3", origin: "https://test2.example.com", sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html", workerURL: "https://test2.example.com/browser/browser/base/content/test/social/social_worker.js", iconURL: "https://test2.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; function test() { waitForExplicitFinish(); let prefname = getManifestPrefname(manifest); // ensure that manifest2 is NOT showing as builtin is(SocialService.getOriginActivationType(manifest.origin), "foreign", "manifest is foreign");
--- a/browser/base/content/test/social/browser_share.js +++ b/browser/base/content/test/social/browser_share.js @@ -43,17 +43,16 @@ function test() { Services.prefs.clearUserPref("social.share.activationPanelEnabled"); }); runSocialTests(tests, undefined, function(next) { let shareButton = SocialShare.shareButton; if (shareButton) { CustomizableUI.removeWidgetFromArea("social-share-button", CustomizableUI.AREA_NAVBAR) shareButton.remove(); } - ok(CustomizableUI.inDefaultState, "Should start in default state."); next(); }); } var corpus = [ { url: baseURL+"opengraph/opengraph.html", options: {
--- a/browser/base/content/test/social/browser_social_contextmenu.js +++ b/browser/base/content/test/social/browser_social_contextmenu.js @@ -8,17 +8,17 @@ var manifest = { // used for testing ins name: "provider test1", origin: "https://test1.example.com", workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js", markURL: "https://test1.example.com/browser/browser/base/content/test/social/social_mark.html?url=%{url}", markedIcon: "https://test1.example.com/browser/browser/base/content/test/social/unchecked.jpg", unmarkedIcon: "https://test1.example.com/browser/browser/base/content/test/social/checked.jpg", iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; function test() { waitForExplicitFinish(); runSocialTestWithProvider(manifest, function (finishcb) { runSocialTests(tests, undefined, undefined, function () { finishcb();
--- a/browser/base/content/test/social/browser_social_marks.js +++ b/browser/base/content/test/social/browser_social_marks.js @@ -8,35 +8,30 @@ var manifest2 = { // used for testing in name: "provider test1", origin: "https://test1.example.com", workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js", markURL: "https://test1.example.com/browser/browser/base/content/test/social/social_mark.html?url=%{url}", markedIcon: "https://test1.example.com/browser/browser/base/content/test/social/unchecked.jpg", unmarkedIcon: "https://test1.example.com/browser/browser/base/content/test/social/checked.jpg", iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; var manifest3 = { // used for testing install name: "provider test2", origin: "https://test2.example.com", sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html", iconURL: "https://test2.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; function test() { waitForExplicitFinish(); - runSocialTests(tests, undefined, undefined, function () { - // Bug 1232207 - something breaks this on aurora on most platforms - // ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish"); - CustomizableUI.reset(); - finish(); - }); + runSocialTests(tests, undefined, undefined, finish); } var tests = { testButtonDisabledOnActivate: function(next) { // starting on about:blank page, share should be visible but disabled when // adding provider is(gBrowser.selectedBrowser.currentURI.spec, "about:blank"); SocialService.addProvider(manifest2, function(provider) {
--- a/browser/base/content/test/social/browser_social_marks_context.js +++ b/browser/base/content/test/social/browser_social_marks_context.js @@ -3,28 +3,24 @@ var SocialService = Cu.import("resource: function makeMarkProvider(origin) { return { // used for testing install name: "mark provider " + origin, origin: "https://" + origin + ".example.com", markURL: "https://" + origin + ".example.com/browser/browser/base/content/test/social/social_mark.html?url=%{url}", markedIcon: "https://" + origin + ".example.com/browser/browser/base/content/test/social/unchecked.jpg", unmarkedIcon: "https://" + origin + ".example.com/browser/browser/base/content/test/social/checked.jpg", iconURL: "https://" + origin + ".example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" } } function test() { waitForExplicitFinish(); - runSocialTests(tests, undefined, undefined, function () { - ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish"); - CustomizableUI.reset(); - finish(); - }); + runSocialTests(tests, undefined, undefined, finish); } var tests = { testContextSubmenu: function(next) { // install 4 providers to test that the menu's are added as submenus let manifests = [ makeMarkProvider("sub1.test1"), makeMarkProvider("sub2.test1"),
--- a/browser/base/content/test/social/browser_social_status.js +++ b/browser/base/content/test/social/browser_social_status.js @@ -12,24 +12,24 @@ var manifest = { // builtin provider iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png" }; var manifest2 = { // used for testing install name: "provider test1", origin: "https://test1.example.com", workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js", statusURL: "https://test1.example.com/browser/browser/base/content/test/social/social_panel.html", iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; var manifest3 = { // used for testing install name: "provider test2", origin: "https://test2.example.com", sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html", iconURL: "https://test2.example.com/browser/browser/base/content/test/general/moz.png", - version: 1 + version: "1.0" }; function openWindowAndWaitForInit(callback) { let topic = "browser-delayed-startup-finished"; let w = OpenBrowserWindow(); Services.obs.addObserver(function providerSet(subject, topic, data) { Services.obs.removeObserver(providerSet, topic); @@ -40,17 +40,16 @@ function openWindowAndWaitForInit(callba function test() { waitForExplicitFinish(); runSocialTestWithProvider(manifest, function (finishcb) { runSocialTests(tests, undefined, undefined, function () { Services.prefs.clearUserPref("social.remote-install.enabled"); // just in case the tests failed, clear these here as well Services.prefs.clearUserPref("social.whitelist"); - ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish"); CustomizableUI.reset(); finishcb(); }); }); } var tests = { testNoButtonOnEnable: function(next) {
--- a/browser/base/content/test/social/social_activate.html +++ b/browser/base/content/test/social/social_activate.html @@ -17,17 +17,17 @@ var data = { "statusURL": "/browser/browser/base/content/test/social/social_panel.html", "postActivationURL": "/browser/browser/base/content/test/social/social_postActivation.html", // should be available for display purposes "description": "A short paragraph about this provider", "author": "Shane Caraveo, Mozilla", // optional - "version": 1 + "version": "1.0" } function activate(node) { node.setAttribute("data-service", JSON.stringify(data)); var event = new CustomEvent("ActivateSocialFeature"); node.dispatchEvent(event); }
--- a/browser/base/content/test/social/social_activate_basic.html +++ b/browser/base/content/test/social/social_activate_basic.html @@ -15,17 +15,17 @@ var data = { "sidebarURL": "/browser/browser/base/content/test/social/social_sidebar_empty.html", "postActivationURL": "/browser/browser/base/content/test/social/social_postActivation.html", // should be available for display purposes "description": "A short paragraph about this provider", "author": "Shane Caraveo, Mozilla", // optional - "version": 1 + "version": "1.0" } function activate(node) { node.setAttribute("data-service", JSON.stringify(data)); var event = new CustomEvent("ActivateSocialFeature"); node.dispatchEvent(event); }
--- a/browser/base/content/test/social/social_worker.js +++ b/browser/base/content/test/social/social_worker.js @@ -121,17 +121,17 @@ onconnect = function(e) { break; case "worker.update": updatingManifest = true; apiPort.postMessage({topic: 'social.manifest-get'}); break; case "social.manifest": if (updatingManifest) { updatingManifest = false; - event.data.data.version = 2; + event.data.data.version = "2.0"; apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data}); } else if (testPort) { testPort.postMessage({topic:"social.manifest", data: event.data.data}); } break; } } }
--- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -121,28 +121,16 @@ static RedirEntry kRedirMap[] = { // Shares an IndexedDB origin with about:loopconversation. "loopconversation" }, { "reader", "chrome://global/content/reader/aboutReader.html", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::MAKE_UNLINKABLE | nsIAboutModule::HIDE_FROM_ABOUTABOUT }, - { - "pocket-saved", "chrome://browser/content/pocket/panels/saved.html", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT | - nsIAboutModule::MAKE_UNLINKABLE }, - { - "pocket-signup", "chrome://browser/content/pocket/panels/signup.html", - nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | - nsIAboutModule::ALLOW_SCRIPT | - nsIAboutModule::HIDE_FROM_ABOUTABOUT | - nsIAboutModule::MAKE_UNLINKABLE }, }; static const int kRedirTotal = ArrayLength(kRedirMap); static nsAutoCString GetAboutModuleName(nsIURI *aURI) { nsAutoCString path; aURI->GetPath(path);
--- a/browser/components/build/nsModule.cpp +++ b/browser/components/build/nsModule.cpp @@ -112,18 +112,16 @@ static const mozilla::Module::ContractID #ifdef MOZ_SERVICES_HEALTHREPORT { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "debugging", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "loopconversation", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, - { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-saved", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, - { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-signup", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #if defined(XP_WIN) { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID }, { NS_EDGEREADINGLISTEXTRACTOR_CONTRACTID, &kNS_EDGEREADINGLISTEXTRACTOR_CID }, #elif defined(XP_MACOSX) { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID }, #endif { nullptr } };
--- a/browser/components/customizableui/CustomizableUI.jsm +++ b/browser/components/customizableui/CustomizableUI.jsm @@ -51,25 +51,26 @@ const kSubviewEvents = [ "ViewShowing", "ViewHiding" ]; /** * The current version. We can use this to auto-add new default widgets as necessary. * (would be const but isn't because of testing purposes) */ -var kVersion = 5; +var kVersion = 6; /** * Buttons removed from built-ins by version they were removed. kVersion must be * bumped any time a new id is added to this. Use the button id as key, and * version the button is removed in as the value. e.g. "pocket-button": 5 */ var ObsoleteBuiltinButtons = { - "loop-button": 5 + "loop-button": 5, + "pocket-button": 6 }; /** * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed * on their IDs. */ var gPalette = new Map(); @@ -217,25 +218,16 @@ var CustomizableUIInternal = { "developer-button", #endif "bookmarks-menu-button", "downloads-button", "home-button", "loop-button", ]; - // Insert the Pocket button after the bookmarks button if it's present. - for (let widgetDefinition of CustomizableWidgets) { - if (widgetDefinition.id == "pocket-button") { - let idx = navbarPlacements.indexOf("bookmarks-menu-button") + 1; - navbarPlacements.splice(idx, 0, widgetDefinition.id); - break; - } - } - if (Services.prefs.getBoolPref(kPrefWebIDEInNavbar)) { navbarPlacements.push("webide-button"); } this.registerArea(CustomizableUI.AREA_NAVBAR, { legacy: true, type: CustomizableUI.TYPE_TOOLBAR, overflowable: true, @@ -3468,18 +3460,18 @@ this.CustomizableUI = { * position: 42 // the index in the placements array corresponding to * // your widget. * } * * OR * * null // if the widget is not placed anywhere (ie in the palette) */ - getPlacementOfWidget: function(aWidgetId) { - return CustomizableUIInternal.getPlacementOfWidget(aWidgetId, true); + getPlacementOfWidget: function(aWidgetId, aOnlyRegistered=true, aDeadAreas=false) { + return CustomizableUIInternal.getPlacementOfWidget(aWidgetId, aOnlyRegistered, aDeadAreas); }, /** * Check if a widget can be removed from the area it's in. * * Note that if you're wanting to move the widget somewhere, you should * generally be checking canWidgetMoveToArea, because that will return * true if the widget is already in the area where you want to move it (!). *
--- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -13,28 +13,22 @@ Cu.import("resource://gre/modules/XPCOMU XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry", "resource:///modules/BrowserUITelemetry.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils", "resource:///modules/PlacesUIUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils", "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Pocket", - "resource:///modules/Pocket.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils", "resource://gre/modules/ShortcutUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu", "resource://gre/modules/CharsetMenu.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", - "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "SocialService", - "resource://gre/modules/SocialService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "SyncedTabs", "resource://services-sync/SyncedTabs.jsm"); XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() { const kCharsetBundle = "chrome://global/locale/charsetMenu.properties"; return Services.strings.createBundle(kCharsetBundle); }); XPCOMUtils.defineLazyGetter(this, "BrandBundle", function() { @@ -1220,78 +1214,16 @@ if (Services.prefs.getBoolPref("privacy. }, onViewHiding: function(aEvent) { let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button"); forgetButton.removeEventListener("command", this); }, }); } -if (Services.prefs.getBoolPref("browser.pocket.enabled")) { - let isEnabledForLocale = true; - if (Services.prefs.getBoolPref("browser.pocket.useLocaleList")) { - let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry); - let browserLocale = chromeRegistry.getSelectedLocale("browser"); - let enabledLocales = []; - try { - enabledLocales = Services.prefs.getCharPref("browser.pocket.enabledLocales").split(' '); - } catch (ex) { - Cu.reportError(ex); - } - isEnabledForLocale = enabledLocales.indexOf(browserLocale) != -1; - } - - if (isEnabledForLocale) { - let pocketButton = { - id: "pocket-button", - defaultArea: CustomizableUI.AREA_NAVBAR, - introducedInVersion: "pref", - type: "view", - viewId: "PanelUI-pocketView", - // Use forwarding functions here to avoid loading Pocket.jsm on startup: - onViewShowing: function() { - return Pocket.onPanelViewShowing.apply(this, arguments); - }, - onViewHiding: function() { - return Pocket.onPanelViewHiding.apply(this, arguments); - }, - - // If the user has the "classic" Pocket add-on installed, use that instead - // and destroy the widget. - conditionalDestroyPromise: new Promise(resolve => { - AddonManager.getAddonByID("isreaditlater@ideashower.com", addon => { - resolve(addon && addon.isActive); - }); - }), - }; - - CustomizableWidgets.push(pocketButton); - CustomizableUI.addListener(pocketButton); - - // Uninstall the Pocket social provider if it exists, but only if we haven't - // already uninstalled it in this manner. That way the user can reinstall - // it if they prefer it without its being uninstalled every time they start - // the browser. - let origin = "https://getpocket.com"; - SocialService.getProvider(origin, provider => { - if (provider) { - let pref = "social.backup.getpocket-com"; - if (!Services.prefs.prefHasUserValue(pref)) { - let str = Cc["@mozilla.org/supports-string;1"]. - createInstance(Ci.nsISupportsString); - str.data = JSON.stringify(provider.manifest); - Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); - SocialService.uninstallProvider(origin, () => {}); - } - } - }); - } -} - #ifdef E10S_TESTING_ONLY var e10sDisabled = false; #ifdef XP_MACOSX // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces // a fallback to Basic Layers. This is incompatible with e10s. e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled"); #endif
--- a/browser/components/customizableui/content/panelUI.inc.xul +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -186,20 +186,16 @@ <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView"> <label value="&bookmarksMenu.label;" class="panel-subview-header"/> <vbox class="panel-subview-body"> <toolbarbutton id="panelMenuBookmarkThisPage" class="subviewbutton" observes="bookmarkThisPageBroadcaster" command="Browser:AddBookmarkAs" onclick="PanelUI.hide();"/> - <toolbarseparator id="panelMenu_pocketSeparator"/> - <toolbarbutton id="panelMenu_pocket" label="&pocketMenuitem.label;" - class="subviewbutton cui-withicon" - oncommand="openUILink(Pocket.listURL, event);"/> <toolbarseparator/> <toolbarbutton id="panelMenu_viewBookmarksSidebar" label="&viewBookmarksSidebar2.label;" class="subviewbutton" key="viewBookmarksSidebarKb" oncommand="SidebarUI.toggle('viewBookmarksSidebar'); PanelUI.hide();"> <observes element="viewBookmarksSidebar" attribute="checked"/> </toolbarbutton> @@ -305,22 +301,16 @@ <label id="PanelUI-panic-warning">&panicButton.view.undoWarning;</label> </vbox> <button id="PanelUI-panic-view-button" label="&panicButton.view.forgetButton;"/> </vbox> </panelview> - <panelview id="PanelUI-pocketView" flex="1"> - <vbox class="panel-subview-body"> - </vbox> - </panelview> - - </panelmultiview> <!-- These menupopups are located here to prevent flickering, see bug 492960 comment 20. --> <menupopup id="customizationPanelItemContextMenu"> <menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)" closemenu="single" class="customize-context-moveToToolbar" accesskey="&customizeMenu.moveToToolbar.accesskey;"
--- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -10,17 +10,16 @@ DIRS += [ 'customizableui', 'dirprovider', 'downloads', 'extensions', 'feeds', 'migration', 'newtab', 'places', - 'pocket', 'preferences', 'privatebrowsing', 'search', 'sessionstore', 'shell', 'selfsupport', 'uitour', 'translation',
deleted file mode 100644 --- a/browser/components/pocket/jar.mn +++ /dev/null @@ -1,48 +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/. - -browser.jar: - content/browser/pocket/main.js - content/browser/pocket/pktApi.js - content/browser/pocket/panels/saved.html (panels/saved.html) - content/browser/pocket/panels/signup.html (panels/signup.html) - content/browser/pocket/panels/css/normalize.css (panels/css/normalize.css) - content/browser/pocket/panels/css/firasans.css (panels/css/firasans.css) - content/browser/pocket/panels/css/saved.css (panels/css/saved.css) - content/browser/pocket/panels/css/signup.css (panels/css/signup.css) - content/browser/pocket/panels/fonts/FiraSans-Regular.woff (panels/fonts/FiraSans-Regular.woff) - content/browser/pocket/panels/img/pocketerror@1x.png (panels/img/pocketerror@1x.png) - content/browser/pocket/panels/img/pocketerror@2x.png (panels/img/pocketerror@2x.png) - content/browser/pocket/panels/img/pocketlogo@1x.png (panels/img/pocketlogo@1x.png) - content/browser/pocket/panels/img/pocketlogo@2x.png (panels/img/pocketlogo@2x.png) - content/browser/pocket/panels/img/pocketlogosolo@1x.png (panels/img/pocketlogosolo@1x.png) - content/browser/pocket/panels/img/pocketlogosolo@2x.png (panels/img/pocketlogosolo@2x.png) - content/browser/pocket/panels/img/pocketmenuitem16.png (panels/img/pocketmenuitem16.png) - content/browser/pocket/panels/img/pocketmenuitem16@2x.png (panels/img/pocketmenuitem16@2x.png) - content/browser/pocket/panels/img/pocketsignup_button@1x.png (panels/img/pocketsignup_button@1x.png) - content/browser/pocket/panels/img/pocketsignup_button@2x.png (panels/img/pocketsignup_button@2x.png) - content/browser/pocket/panels/img/pocketsignup_devices@1x.png (panels/img/pocketsignup_devices@1x.png) - content/browser/pocket/panels/img/pocketsignup_devices@2x.png (panels/img/pocketsignup_devices@2x.png) - content/browser/pocket/panels/img/pocketsignup_hero@1x.png (panels/img/pocketsignup_hero@1x.png) - content/browser/pocket/panels/img/pocketsignup_hero@2x.png (panels/img/pocketsignup_hero@2x.png) - content/browser/pocket/panels/img/signup_firefoxlogo@1x.png (panels/img/signup_firefoxlogo@1x.png) - content/browser/pocket/panels/img/signup_firefoxlogo@2x.png (panels/img/signup_firefoxlogo@2x.png) - content/browser/pocket/panels/img/signup_help@1x.png (panels/img/signup_help@1x.png) - content/browser/pocket/panels/img/signup_help@2x.png (panels/img/signup_help@2x.png) - content/browser/pocket/panels/img/tag_close@1x.png (panels/img/tag_close@1x.png) - content/browser/pocket/panels/img/tag_close@2x.png (panels/img/tag_close@2x.png) - content/browser/pocket/panels/img/tag_closeactive@1x.png (panels/img/tag_closeactive@1x.png) - content/browser/pocket/panels/img/tag_closeactive@2x.png (panels/img/tag_closeactive@2x.png) - content/browser/pocket/panels/js/messages.js (panels/js/messages.js) - content/browser/pocket/panels/js/saved.js (panels/js/saved.js) - content/browser/pocket/panels/js/signup.js (panels/js/signup.js) - content/browser/pocket/panels/js/tmpl.js (panels/js/tmpl.js) - content/browser/pocket/panels/js/vendor/jquery-2.1.1.min.js (panels/js/vendor/jquery-2.1.1.min.js) - content/browser/pocket/panels/js/vendor/handlebars.runtime.js (panels/js/vendor/handlebars.runtime.js) - content/browser/pocket/panels/js/vendor/jquery.tokeninput.min.js (panels/js/vendor/jquery.tokeninput.min.js) - content/browser/pocket/panels/tmpl/saved_premiumextras.handlebars (panels/tmpl/saved_premiumextras.handlebars) - content/browser/pocket/panels/tmpl/saved_premiumshell.handlebars (panels/tmpl/saved_premiumshell.handlebars) - content/browser/pocket/panels/tmpl/saved_shell.handlebars (panels/tmpl/saved_shell.handlebars) - content/browser/pocket/panels/tmpl/signup_shell.handlebars (panels/tmpl/signup_shell.handlebars) - content/browser/pocket/panels/tmpl/signupstoryboard_shell.handlebars (panels/tmpl/signupstoryboard_shell.handlebars)
deleted file mode 100644 --- a/browser/components/pocket/moz.build +++ /dev/null @@ -1,7 +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/. - -JAR_MANIFESTS += ['jar.mn'] - -EXTRA_JS_MODULES += ['Pocket.jsm']
--- a/browser/components/uitour/test/browser_UITour_availableTargets.js +++ b/browser/components/uitour/test/browser_UITour_availableTargets.js @@ -4,35 +4,17 @@ "use strict"; var gTestTab; var gContentAPI; var gContentWindow; var hasWebIDE = Services.prefs.getBoolPref("devtools.webide.widget.enabled"); -var hasPocket = false; -if (Services.prefs.getBoolPref("browser.pocket.enabled")) { - let isEnabledForLocale = true; - if (Services.prefs.getBoolPref("browser.pocket.useLocaleList")) { - let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry); - let browserLocale = chromeRegistry.getSelectedLocale("browser"); - let enabledLocales = []; - try { - enabledLocales = Services.prefs.getCharPref("browser.pocket.enabledLocales").split(' '); - } catch (ex) { - Cu.reportError(ex); - } - isEnabledForLocale = enabledLocales.indexOf(browserLocale) != -1; - } - if (isEnabledForLocale) { - hasPocket = true; - } -} +var hasPocket = Services.prefs.getBoolPref("extensions.pocket.enabled"); function test() { requestLongerTimeout(2); UITourTest(); } var tests = [ function test_availableTargets(done) {
--- a/browser/components/uitour/test/browser_UITour_pocket.js +++ b/browser/components/uitour/test/browser_UITour_pocket.js @@ -57,17 +57,17 @@ function checkPanelIsHidden(aPanel) { if (aPanel.parentElement) { is_hidden(aPanel); } else { ok(!aPanel.parentElement, "Widget panel should have been removed"); } is(button.hasAttribute("open"), false, "Pocket button should know that the panel is closed"); } -if (Services.prefs.getBoolPref("browser.pocket.enabled")) { +if (Services.prefs.getBoolPref("extensions.pocket.enabled")) { let placement = CustomizableUI.getPlacementOfWidget("pocket-button"); // Add the button to the nav-bar by default. if (!placement || placement.area != CustomizableUI.AREA_NAVBAR) { CustomizableUI.addWidgetToArea("pocket-button", CustomizableUI.AREA_NAVBAR); } registerCleanupFunction(() => { CustomizableUI.reset();
--- a/browser/extensions/moz.build +++ b/browser/extensions/moz.build @@ -2,10 +2,11 @@ # 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/. DIRS += [ 'loop', 'pdfjs', + 'pocket', 'shumway', ]
--- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,3 +1,3 @@ This is the pdf.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 1.3.110 +Current extension version is: 1.3.142
--- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -7,26 +7,27 @@ * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ -/*jshint globalstrict: false */ -/* globals PDFJS */ +/* jshint globalstrict: false */ +/* globals PDFJS, global */ // Initializing PDFJS global object (if still undefined) if (typeof PDFJS === 'undefined') { - (typeof window !== 'undefined' ? window : this).PDFJS = {}; + (typeof window !== 'undefined' ? window : + typeof global !== 'undefined' ? global : this).PDFJS = {}; } -PDFJS.version = '1.3.110'; -PDFJS.build = '42beb0c'; +PDFJS.version = '1.3.142'; +PDFJS.build = 'e8db825'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it 'use strict'; (function (root, factory) { @@ -53,16 +54,84 @@ PDFJS.build = '42beb0c'; exports.globalScope = globalScope; exports.isWorker = isWorker; exports.PDFJS = globalScope.PDFJS; })); (function (root, factory) { { + factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedGlobal); + } +}(this, function (exports, sharedGlobal) { + +var PDFJS = sharedGlobal.PDFJS; + +/** + * Optimised CSS custom property getter/setter. + * @class + */ +var CustomStyle = (function CustomStyleClosure() { + + // As noted on: http://www.zachstronaut.com/posts/2009/02/17/ + // animate-css-transforms-firefox-webkit.html + // in some versions of IE9 it is critical that ms appear in this list + // before Moz + var prefixes = ['ms', 'Moz', 'Webkit', 'O']; + var _cache = {}; + + function CustomStyle() {} + + CustomStyle.getProp = function get(propName, element) { + // check cache only when no element is given + if (arguments.length === 1 && typeof _cache[propName] === 'string') { + return _cache[propName]; + } + + element = element || document.documentElement; + var style = element.style, prefixed, uPropName; + + // test standard property first + if (typeof style[propName] === 'string') { + return (_cache[propName] = propName); + } + + // capitalize + uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); + + // test vendor specific properties + for (var i = 0, l = prefixes.length; i < l; i++) { + prefixed = prefixes[i] + uPropName; + if (typeof style[prefixed] === 'string') { + return (_cache[propName] = prefixed); + } + } + + //if all fails then set to undefined + return (_cache[propName] = 'undefined'); + }; + + CustomStyle.setProp = function set(propName, element, str) { + var prop = this.getProp(propName); + if (prop !== 'undefined') { + element.style[prop] = str; + } + }; + + return CustomStyle; +})(); + +PDFJS.CustomStyle = CustomStyle; + +exports.CustomStyle = CustomStyle; +})); + + +(function (root, factory) { + { factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedGlobal); } }(this, function (exports, sharedGlobal) { var PDFJS = sharedGlobal.PDFJS; var globalScope = sharedGlobal.globalScope; var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; @@ -1400,434 +1469,688 @@ exports.stringToPDFString = stringToPDFS exports.stringToUTF8String = stringToUTF8String; exports.utf8StringToString = utf8StringToString; exports.warn = warn; })); (function (root, factory) { { - factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedGlobal); - } -}(this, function (exports, sharedGlobal) { - -var PDFJS = sharedGlobal.PDFJS; - -/** - * Optimised CSS custom property getter/setter. - * @class - */ -var CustomStyle = (function CustomStyleClosure() { - - // As noted on: http://www.zachstronaut.com/posts/2009/02/17/ - // animate-css-transforms-firefox-webkit.html - // in some versions of IE9 it is critical that ms appear in this list - // before Moz - var prefixes = ['ms', 'Moz', 'Webkit', 'O']; - var _cache = {}; - - function CustomStyle() {} - - CustomStyle.getProp = function get(propName, element) { - // check cache only when no element is given - if (arguments.length === 1 && typeof _cache[propName] === 'string') { - return _cache[propName]; - } - - element = element || document.documentElement; - var style = element.style, prefixed, uPropName; - - // test standard property first - if (typeof style[propName] === 'string') { - return (_cache[propName] = propName); - } - - // capitalize - uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); - - // test vendor specific properties - for (var i = 0, l = prefixes.length; i < l; i++) { - prefixed = prefixes[i] + uPropName; - if (typeof style[prefixed] === 'string') { - return (_cache[propName] = prefixed); - } - } - - //if all fails then set to undefined - return (_cache[propName] = 'undefined'); - }; - - CustomStyle.setProp = function set(propName, element, str) { - var prop = this.getProp(propName); - if (prop !== 'undefined') { - element.style[prop] = str; - } - }; - - return CustomStyle; -})(); - -PDFJS.CustomStyle = CustomStyle; - -exports.CustomStyle = CustomStyle; -})); - - -(function (root, factory) { - { factory((root.pdfjsDisplayAnnotationLayer = {}), root.pdfjsSharedUtil, root.pdfjsDisplayDOMUtils); } }(this, function (exports, sharedUtil, displayDOMUtils) { var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType; var AnnotationType = sharedUtil.AnnotationType; var Util = sharedUtil.Util; -var isExternalLinkTargetSet = sharedUtil.Util; +var isExternalLinkTargetSet = sharedUtil.isExternalLinkTargetSet; var LinkTargetStringMap = sharedUtil.LinkTargetStringMap; var warn = sharedUtil.warn; var CustomStyle = displayDOMUtils.CustomStyle; -var ANNOT_MIN_SIZE = 10; // px - -var AnnotationLayer = (function AnnotationLayerClosure() { - // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont() - function setTextStyles(element, item, fontObj) { - var style = element.style; - style.fontSize = item.fontSize + 'px'; - style.direction = item.fontDirection < 0 ? 'rtl': 'ltr'; - - if (!fontObj) { - return; +/** + * @typedef {Object} AnnotationElementParameters + * @property {Object} data + * @property {HTMLDivElement} layer + * @property {PDFPage} page + * @property {PageViewport} viewport + * @property {IPDFLinkService} linkService + */ + +/** + * @class + * @alias AnnotationElementFactory + */ +function AnnotationElementFactory() {} +AnnotationElementFactory.prototype = + /** @lends AnnotationElementFactory.prototype */ { + /** + * @param {AnnotationElementParameters} parameters + * @returns {AnnotationElement} + */ + create: function AnnotationElementFactory_create(parameters) { + var subtype = parameters.data.annotationType; + + switch (subtype) { + case AnnotationType.LINK: + return new LinkAnnotationElement(parameters); + + case AnnotationType.TEXT: + return new TextAnnotationElement(parameters); + + case AnnotationType.WIDGET: + return new WidgetAnnotationElement(parameters); + + case AnnotationType.POPUP: + return new PopupAnnotationElement(parameters); + + case AnnotationType.UNDERLINE: + return new UnderlineAnnotationElement(parameters); + + default: + throw new Error('Unimplemented annotation type "' + subtype + '"'); } - - style.fontWeight = fontObj.black ? - (fontObj.bold ? 'bolder' : 'bold') : - (fontObj.bold ? 'bold' : 'normal'); - style.fontStyle = fontObj.italic ? 'italic' : 'normal'; - - var fontName = fontObj.loadedName; - var fontFamily = fontName ? '"' + fontName + '", ' : ''; - // Use a reasonable default font if the font doesn't specify a fallback - var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif'; - style.fontFamily = fontFamily + fallbackName; } - - function getContainer(data, page, viewport) { - var container = document.createElement('section'); - var width = data.rect[2] - data.rect[0]; - var height = data.rect[3] - data.rect[1]; - - container.setAttribute('data-annotation-id', data.id); - - data.rect = Util.normalizeRect([ - data.rect[0], - page.view[3] - data.rect[1] + page.view[1], - data.rect[2], - page.view[3] - data.rect[3] + page.view[1] - ]); - - CustomStyle.setProp('transform', container, - 'matrix(' + viewport.transform.join(',') + ')'); - CustomStyle.setProp('transformOrigin', container, - -data.rect[0] + 'px ' + -data.rect[1] + 'px'); - - if (data.borderStyle.width > 0) { - container.style.borderWidth = data.borderStyle.width + 'px'; - if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) { - // Underline styles only have a bottom border, so we do not need - // to adjust for all borders. This yields a similar result as - // Adobe Acrobat/Reader. - width = width - 2 * data.borderStyle.width; - height = height - 2 * data.borderStyle.width; - } - - var horizontalRadius = data.borderStyle.horizontalCornerRadius; - var verticalRadius = data.borderStyle.verticalCornerRadius; - if (horizontalRadius > 0 || verticalRadius > 0) { - var radius = horizontalRadius + 'px / ' + verticalRadius + 'px'; - CustomStyle.setProp('borderRadius', container, radius); - } - - switch (data.borderStyle.style) { - case AnnotationBorderStyleType.SOLID: - container.style.borderStyle = 'solid'; - break; - - case AnnotationBorderStyleType.DASHED: - container.style.borderStyle = 'dashed'; - break; - - case AnnotationBorderStyleType.BEVELED: - warn('Unimplemented border style: beveled'); - break; - - case AnnotationBorderStyleType.INSET: - warn('Unimplemented border style: inset'); - break; - - case AnnotationBorderStyleType.UNDERLINE: - container.style.borderBottomStyle = 'solid'; - break; - - default: - break; - } - - if (data.color) { - container.style.borderColor = - Util.makeCssRgb(data.color[0] | 0, - data.color[1] | 0, - data.color[2] | 0); - } else { - // Transparent (invisible) border, so do not draw it at all. - container.style.borderWidth = 0; - } - } - - container.style.left = data.rect[0] + 'px'; - container.style.top = data.rect[1] + 'px'; - - container.style.width = width + 'px'; - container.style.height = height + 'px'; - - return container; - } - - function getHtmlElementForTextWidgetAnnotation(item, page, viewport) { - var container = getContainer(item, page, viewport); - - var content = document.createElement('div'); - content.textContent = item.fieldValue; - var textAlignment = item.textAlignment; - content.style.textAlign = ['left', 'center', 'right'][textAlignment]; - content.style.verticalAlign = 'middle'; - content.style.display = 'table-cell'; - - var fontObj = item.fontRefName ? - page.commonObjs.getData(item.fontRefName) : null; - setTextStyles(content, item, fontObj); - - container.appendChild(content); - - return container; +}; + +/** + * @class + * @alias AnnotationElement + */ +var AnnotationElement = (function AnnotationElementClosure() { + function AnnotationElement(parameters) { + this.data = parameters.data; + this.layer = parameters.layer; + this.page = parameters.page; + this.viewport = parameters.viewport; + this.linkService = parameters.linkService; + + this.container = this._createContainer(); } - function getHtmlElementForTextAnnotation(item, page, viewport) { - var rect = item.rect; - - // sanity check because of OOo-generated PDFs - if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) { - rect[3] = rect[1] + ANNOT_MIN_SIZE; - } - if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) { - rect[2] = rect[0] + (rect[3] - rect[1]); // make it square - } - - var container = getContainer(item, page, viewport); - container.className = 'annotText'; - - var image = document.createElement('img'); - image.style.height = container.style.height; - image.style.width = container.style.width; - var iconName = item.name; - image.src = PDFJS.imageResourcesPath + 'annotation-' + - iconName.toLowerCase() + '.svg'; - image.alt = '[{{type}} Annotation]'; - image.dataset.l10nId = 'text_annotation_type'; - image.dataset.l10nArgs = JSON.stringify({type: iconName}); - - var contentWrapper = document.createElement('div'); - contentWrapper.className = 'annotTextContentWrapper'; - contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px'; - contentWrapper.style.top = '-10px'; - - var content = document.createElement('div'); - content.className = 'annotTextContent'; - content.setAttribute('hidden', true); - - var i, ii; - if (item.hasBgColor && item.color) { - var color = item.color; - - // Enlighten the color (70%) - var BACKGROUND_ENLIGHT = 0.7; - var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; - var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; - var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; - content.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0); - } - - var title = document.createElement('h1'); - var text = document.createElement('p'); - title.textContent = item.title; - - if (!item.content && !item.title) { - content.setAttribute('hidden', true); - } else { - var e = document.createElement('span'); - var lines = item.content.split(/(?:\r\n?|\n)/); - for (i = 0, ii = lines.length; i < ii; ++i) { - var line = lines[i]; - e.appendChild(document.createTextNode(line)); - if (i < (ii - 1)) { - e.appendChild(document.createElement('br')); + AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ { + /** + * Create an empty container for the annotation's HTML element. + * + * @private + * @memberof AnnotationElement + * @returns {HTMLSectionElement} + */ + _createContainer: function AnnotationElement_createContainer() { + var data = this.data, page = this.page, viewport = this.viewport; + var container = document.createElement('section'); + var width = data.rect[2] - data.rect[0]; + var height = data.rect[3] - data.rect[1]; + + container.setAttribute('data-annotation-id', data.id); + + // Do *not* modify `data.rect`, since that will corrupt the annotation + // position on subsequent calls to `_createContainer` (see issue 6804). + var rect = Util.normalizeRect([ + data.rect[0], + page.view[3] - data.rect[1] + page.view[1], + data.rect[2], + page.view[3] - data.rect[3] + page.view[1] + ]); + + CustomStyle.setProp('transform', container, + 'matrix(' + viewport.transform.join(',') + ')'); + CustomStyle.setProp('transformOrigin', container, + -rect[0] + 'px ' + -rect[1] + 'px'); + + if (data.borderStyle.width > 0) { + container.style.borderWidth = data.borderStyle.width + 'px'; + if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) { + // Underline styles only have a bottom border, so we do not need + // to adjust for all borders. This yields a similar result as + // Adobe Acrobat/Reader. + width = width - 2 * data.borderStyle.width; + height = height - 2 * data.borderStyle.width; + } + + var horizontalRadius = data.borderStyle.horizontalCornerRadius; + var verticalRadius = data.borderStyle.verticalCornerRadius; + if (horizontalRadius > 0 || verticalRadius > 0) { + var radius = horizontalRadius + 'px / ' + verticalRadius + 'px'; + CustomStyle.setProp('borderRadius', container, radius); + } + + switch (data.borderStyle.style) { + case AnnotationBorderStyleType.SOLID: + container.style.borderStyle = 'solid'; + break; + + case AnnotationBorderStyleType.DASHED: + container.style.borderStyle = 'dashed'; + break; + + case AnnotationBorderStyleType.BEVELED: + warn('Unimplemented border style: beveled'); + break; + + case AnnotationBorderStyleType.INSET: + warn('Unimplemented border style: inset'); + break; + + case AnnotationBorderStyleType.UNDERLINE: + container.style.borderBottomStyle = 'solid'; + break; + + default: + break; + } + + if (data.color) { + container.style.borderColor = + Util.makeCssRgb(data.color[0] | 0, + data.color[1] | 0, + data.color[2] | 0); + } else { + // Transparent (invisible) border, so do not draw it at all. + container.style.borderWidth = 0; } } - text.appendChild(e); - - var pinned = false; - - var showAnnotation = function showAnnotation(pin) { - if (pin) { - pinned = true; - } - if (content.hasAttribute('hidden')) { - container.style.zIndex += 1; - content.removeAttribute('hidden'); - } - }; - - var hideAnnotation = function hideAnnotation(unpin) { - if (unpin) { - pinned = false; - } - if (!content.hasAttribute('hidden') && !pinned) { - container.style.zIndex -= 1; - content.setAttribute('hidden', true); - } - }; - - var toggleAnnotation = function toggleAnnotation() { - if (pinned) { - hideAnnotation(true); + + container.style.left = rect[0] + 'px'; + container.style.top = rect[1] + 'px'; + + container.style.width = width + 'px'; + container.style.height = height + 'px'; + + return container; + }, + + /** + * Render the annotation's HTML element in the empty container. + * + * @public + * @memberof AnnotationElement + */ + render: function AnnotationElement_render() { + throw new Error('Abstract method AnnotationElement.render called'); + } + }; + + return AnnotationElement; +})(); + +/** + * @class + * @alias LinkAnnotationElement + */ +var LinkAnnotationElement = (function LinkAnnotationElementClosure() { + function LinkAnnotationElement(parameters) { + AnnotationElement.call(this, parameters); + } + + Util.inherit(LinkAnnotationElement, AnnotationElement, { + /** + * Render the link annotation's HTML element in the empty container. + * + * @public + * @memberof LinkAnnotationElement + * @returns {HTMLSectionElement} + */ + render: function LinkAnnotationElement_render() { + this.container.className = 'linkAnnotation'; + + var link = document.createElement('a'); + link.href = link.title = this.data.url || ''; + + if (this.data.url && isExternalLinkTargetSet()) { + link.target = LinkTargetStringMap[PDFJS.externalLinkTarget]; + } + + // Strip referrer from the URL. + if (this.data.url) { + link.rel = PDFJS.externalLinkRel; + } + + if (!this.data.url) { + if (this.data.action) { + this._bindNamedAction(link, this.data.action); } else { - showAnnotation(true); + this._bindLink(link, ('dest' in this.data) ? this.data.dest : null); } - }; - - image.addEventListener('click', function image_clickHandler() { - toggleAnnotation(); - }, false); - image.addEventListener('mouseover', function image_mouseOverHandler() { - showAnnotation(); - }, false); - image.addEventListener('mouseout', function image_mouseOutHandler() { - hideAnnotation(); - }, false); - - content.addEventListener('click', function content_clickHandler() { - hideAnnotation(true); - }, false); - } - - content.appendChild(title); - content.appendChild(text); - contentWrapper.appendChild(content); - container.appendChild(image); - container.appendChild(contentWrapper); - - return container; - } - - function getHtmlElementForLinkAnnotation(item, page, viewport, linkService) { - function bindLink(link, dest) { - link.href = linkService.getDestinationHash(dest); - link.onclick = function annotationsLayerBuilderLinksOnclick() { - if (dest) { - linkService.navigateTo(dest); + } + + this.container.appendChild(link); + return this.container; + }, + + /** + * Bind internal links to the link element. + * + * @private + * @param {Object} link + * @param {Object} destination + * @memberof LinkAnnotationElement + */ + _bindLink: function LinkAnnotationElement_bindLink(link, destination) { + var self = this; + + link.href = this.linkService.getDestinationHash(destination); + link.onclick = function() { + if (destination) { + self.linkService.navigateTo(destination); } return false; }; - if (dest) { + if (destination) { link.className = 'internalLink'; } - } - - function bindNamedAction(link, action) { - link.href = linkService.getAnchorUrl(''); - link.onclick = function annotationsLayerBuilderNamedActionOnClick() { - linkService.executeNamedAction(action); + }, + + /** + * Bind named actions to the link element. + * + * @private + * @param {Object} link + * @param {Object} action + * @memberof LinkAnnotationElement + */ + _bindNamedAction: + function LinkAnnotationElement_bindNamedAction(link, action) { + var self = this; + + link.href = this.linkService.getAnchorUrl(''); + link.onclick = function() { + self.linkService.executeNamedAction(action); return false; }; link.className = 'internalLink'; } - - var container = getContainer(item, page, viewport); - container.className = 'annotLink'; - - var link = document.createElement('a'); - link.href = link.title = item.url || ''; - - if (item.url && isExternalLinkTargetSet()) { - link.target = LinkTargetStringMap[PDFJS.externalLinkTarget]; + }); + + return LinkAnnotationElement; +})(); + +/** + * @class + * @alias TextAnnotationElement + */ +var TextAnnotationElement = (function TextAnnotationElementClosure() { + function TextAnnotationElement(parameters) { + AnnotationElement.call(this, parameters); + } + + Util.inherit(TextAnnotationElement, AnnotationElement, { + /** + * Render the text annotation's HTML element in the empty container. + * + * @public + * @memberof TextAnnotationElement + * @returns {HTMLSectionElement} + */ + render: function TextAnnotationElement_render() { + this.container.className = 'textAnnotation'; + + var image = document.createElement('img'); + image.style.height = this.container.style.height; + image.style.width = this.container.style.width; + image.src = PDFJS.imageResourcesPath + 'annotation-' + + this.data.name.toLowerCase() + '.svg'; + image.alt = '[{{type}} Annotation]'; + image.dataset.l10nId = 'text_annotation_type'; + image.dataset.l10nArgs = JSON.stringify({type: this.data.name}); + + if (!this.data.hasPopup) { + var popupElement = new PopupElement({ + container: this.container, + trigger: image, + color: this.data.color, + title: this.data.title, + contents: this.data.contents, + hideWrapper: true + }); + var popup = popupElement.render(); + + // Position the popup next to the Text annotation's container. + popup.style.left = image.style.width; + + this.container.appendChild(popup); + } + + this.container.appendChild(image); + return this.container; + } + }); + + return TextAnnotationElement; +})(); + +/** + * @class + * @alias WidgetAnnotationElement + */ +var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() { + function WidgetAnnotationElement(parameters) { + AnnotationElement.call(this, parameters); + } + + Util.inherit(WidgetAnnotationElement, AnnotationElement, { + /** + * Render the widget annotation's HTML element in the empty container. + * + * @public + * @memberof WidgetAnnotationElement + * @returns {HTMLSectionElement} + */ + render: function WidgetAnnotationElement_render() { + var content = document.createElement('div'); + content.textContent = this.data.fieldValue; + var textAlignment = this.data.textAlignment; + content.style.textAlign = ['left', 'center', 'right'][textAlignment]; + content.style.verticalAlign = 'middle'; + content.style.display = 'table-cell'; + + var font = (this.data.fontRefName ? + this.page.commonObjs.getData(this.data.fontRefName) : null); + this._setTextStyle(content, font); + + this.container.appendChild(content); + return this.container; + }, + + /** + * Apply text styles to the text in the element. + * + * @private + * @param {HTMLDivElement} element + * @param {Object} font + * @memberof WidgetAnnotationElement + */ + _setTextStyle: + function WidgetAnnotationElement_setTextStyle(element, font) { + // TODO: This duplicates some of the logic in CanvasGraphics.setFont(). + var style = element.style; + style.fontSize = this.data.fontSize + 'px'; + style.direction = (this.data.fontDirection < 0 ? 'rtl': 'ltr'); + + if (!font) { + return; + } + + style.fontWeight = (font.black ? + (font.bold ? '900' : 'bold') : + (font.bold ? 'bold' : 'normal')); + style.fontStyle = (font.italic ? 'italic' : 'normal'); + + // Use a reasonable default font if the font doesn't specify a fallback. + var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : ''; + var fallbackName = font.fallbackName || 'Helvetica, sans-serif'; + style.fontFamily = fontFamily + fallbackName; } - - // Strip referrer - if (item.url) { - link.rel = PDFJS.externalLinkRel; + }); + + return WidgetAnnotationElement; +})(); + +/** + * @class + * @alias PopupAnnotationElement + */ +var PopupAnnotationElement = (function PopupAnnotationElementClosure() { + function PopupAnnotationElement(parameters) { + AnnotationElement.call(this, parameters); + } + + Util.inherit(PopupAnnotationElement, AnnotationElement, { + /** + * Render the popup annotation's HTML element in the empty container. + * + * @public + * @memberof PopupAnnotationElement + * @returns {HTMLSectionElement} + */ + render: function PopupAnnotationElement_render() { + this.container.className = 'popupAnnotation'; + + var selector = '[data-annotation-id="' + this.data.parentId + '"]'; + var parentElement = this.layer.querySelector(selector); + if (!parentElement) { + return this.container; + } + + var popup = new PopupElement({ + container: this.container, + trigger: parentElement, + color: this.data.color, + title: this.data.title, + contents: this.data.contents + }); + + // Position the popup next to the parent annotation's container. + // PDF viewers ignore a popup annotation's rectangle. + var parentLeft = parseFloat(parentElement.style.left); + var parentWidth = parseFloat(parentElement.style.width); + CustomStyle.setProp('transformOrigin', this.container, + -(parentLeft + parentWidth) + 'px -' + + parentElement.style.top); + this.container.style.left = (parentLeft + parentWidth) + 'px'; + + this.container.appendChild(popup.render()); + return this.container; } - - if (!item.url) { - if (item.action) { - bindNamedAction(link, item.action); + }); + + return PopupAnnotationElement; +})(); + +/** + * @class + * @alias PopupElement + */ +var PopupElement = (function PopupElementClosure() { + var BACKGROUND_ENLIGHT = 0.7; + + function PopupElement(parameters) { + this.container = parameters.container; + this.trigger = parameters.trigger; + this.color = parameters.color; + this.title = parameters.title; + this.contents = parameters.contents; + this.hideWrapper = parameters.hideWrapper || false; + + this.pinned = false; + } + + PopupElement.prototype = /** @lends PopupElement.prototype */ { + /** + * Render the popup's HTML element. + * + * @public + * @memberof PopupElement + * @returns {HTMLSectionElement} + */ + render: function PopupElement_render() { + var wrapper = document.createElement('div'); + wrapper.className = 'popupWrapper'; + + // For Popup annotations we hide the entire section because it contains + // only the popup. However, for Text annotations without a separate Popup + // annotation, we cannot hide the entire container as the image would + // disappear too. In that special case, hiding the wrapper suffices. + this.hideElement = (this.hideWrapper ? wrapper : this.container); + this.hideElement.setAttribute('hidden', true); + + var popup = document.createElement('div'); + popup.className = 'popup'; + + var color = this.color; + if (color) { + // Enlighten the color. + var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; + var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; + var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; + popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0); + } + + var contents = this._formatContents(this.contents); + var title = document.createElement('h1'); + title.textContent = this.title; + + // Attach the event listeners to the trigger element. + this.trigger.addEventListener('click', this._toggle.bind(this)); + this.trigger.addEventListener('mouseover', this._show.bind(this, false)); + this.trigger.addEventListener('mouseout', this._hide.bind(this, false)); + popup.addEventListener('click', this._hide.bind(this, true)); + + popup.appendChild(title); + popup.appendChild(contents); + wrapper.appendChild(popup); + return wrapper; + }, + + /** + * Format the contents of the popup by adding newlines where necessary. + * + * @private + * @param {string} contents + * @memberof PopupElement + * @returns {HTMLParagraphElement} + */ + _formatContents: function PopupElement_formatContents(contents) { + var p = document.createElement('p'); + var lines = contents.split(/(?:\r\n?|\n)/); + for (var i = 0, ii = lines.length; i < ii; ++i) { + var line = lines[i]; + p.appendChild(document.createTextNode(line)); + if (i < (ii - 1)) { + p.appendChild(document.createElement('br')); + } + } + return p; + }, + + /** + * Toggle the visibility of the popup. + * + * @private + * @memberof PopupElement + */ + _toggle: function PopupElement_toggle() { + if (this.pinned) { + this._hide(true); } else { - bindLink(link, ('dest' in item) ? item.dest : null); + this._show(true); + } + }, + + /** + * Show the popup. + * + * @private + * @param {boolean} pin + * @memberof PopupElement + */ + _show: function PopupElement_show(pin) { + if (pin) { + this.pinned = true; + } + if (this.hideElement.hasAttribute('hidden')) { + this.hideElement.removeAttribute('hidden'); + this.container.style.zIndex += 1; + } + }, + + /** + * Hide the popup. + * + * @private + * @param {boolean} unpin + * @memberof PopupElement + */ + _hide: function PopupElement_hide(unpin) { + if (unpin) { + this.pinned = false; + } + if (!this.hideElement.hasAttribute('hidden') && !this.pinned) { + this.hideElement.setAttribute('hidden', true); + this.container.style.zIndex -= 1; } } - - container.appendChild(link); - - return container; - } - - function getHtmlElement(data, page, viewport, linkService) { - switch (data.annotationType) { - case AnnotationType.WIDGET: - return getHtmlElementForTextWidgetAnnotation(data, page, viewport); - case AnnotationType.TEXT: - return getHtmlElementForTextAnnotation(data, page, viewport); - case AnnotationType.LINK: - return getHtmlElementForLinkAnnotation(data, page, viewport, - linkService); - default: - throw new Error('Unsupported annotationType: ' + data.annotationType); - } + }; + + return PopupElement; +})(); + +/** + * @class + * @alias UnderlineAnnotationElement + */ +var UnderlineAnnotationElement = ( + function UnderlineAnnotationElementClosure() { + function UnderlineAnnotationElement(parameters) { + AnnotationElement.call(this, parameters); } - function render(viewport, div, annotations, page, linkService) { - for (var i = 0, ii = annotations.length; i < ii; i++) { - var data = annotations[i]; - if (!data || !data.hasHtml) { - continue; - } - - var element = getHtmlElement(data, page, viewport, linkService); - div.appendChild(element); + Util.inherit(UnderlineAnnotationElement, AnnotationElement, { + /** + * Render the underline annotation's HTML element in the empty container. + * + * @public + * @memberof UnderlineAnnotationElement + * @returns {HTMLSectionElement} + */ + render: function UnderlineAnnotationElement_render() { + this.container.className = 'underlineAnnotation'; + return this.container; } - } - - function update(viewport, div, annotations) { - for (var i = 0, ii = annotations.length; i < ii; i++) { - var data = annotations[i]; - var element = div.querySelector( - '[data-annotation-id="' + data.id + '"]'); - if (element) { - CustomStyle.setProp('transform', element, - 'matrix(' + viewport.transform.join(',') + ')'); - } + }); + + return UnderlineAnnotationElement; +})(); + +/** + * @typedef {Object} AnnotationLayerParameters + * @property {PageViewport} viewport + * @property {HTMLDivElement} div + * @property {Array} annotations + * @property {PDFPage} page + * @property {IPDFLinkService} linkService + */ + +/** + * @class + * @alias AnnotationLayer + */ +var AnnotationLayer = (function AnnotationLayerClosure() { + return { + /** + * Render a new annotation layer with all annotation elements. + * + * @public + * @param {AnnotationLayerParameters} parameters + * @memberof AnnotationLayer + */ + render: function AnnotationLayer_render(parameters) { + var annotationElementFactory = new AnnotationElementFactory(); + + for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { + var data = parameters.annotations[i]; + if (!data || !data.hasHtml) { + continue; + } + + var properties = { + data: data, + layer: parameters.div, + page: parameters.page, + viewport: parameters.viewport, + linkService: parameters.linkService + }; + var element = annotationElementFactory.create(properties); + parameters.div.appendChild(element.render()); + } + }, + + /** + * Update the annotation elements on existing annotation layer. + * + * @public + * @param {AnnotationLayerParameters} parameters + * @memberof AnnotationLayer + */ + update: function AnnotationLayer_update(parameters) { + for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { + var data = parameters.annotations[i]; + var element = parameters.div.querySelector( + '[data-annotation-id="' + data.id + '"]'); + if (element) { + CustomStyle.setProp('transform', element, + 'matrix(' + parameters.viewport.transform.join(',') + ')'); + } + } + parameters.div.removeAttribute('hidden'); } - div.removeAttribute('hidden'); - } - - return { - render: render, - update: update }; })(); + PDFJS.AnnotationLayer = AnnotationLayer; exports.AnnotationLayer = AnnotationLayer; })); (function (root, factory) { { @@ -2080,21 +2403,25 @@ var Metadata = PDFJS.Metadata = (functio })(); exports.Metadata = Metadata; })); (function (root, factory) { { - factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil); + factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil, + root.pdfjsDisplayDOMUtils, root.pdfjsSharedGlobal); } -}(this, function (exports, sharedUtil) { - +}(this, function (exports, sharedUtil, displayDOMUtils, sharedGlobal) { + +var Util = sharedUtil.Util; var createPromiseCapability = sharedUtil.createPromiseCapability; +var CustomStyle = displayDOMUtils.CustomStyle; +var PDFJS = sharedGlobal.PDFJS; /** * Text layer render parameters. * * @typedef {Object} TextLayerRenderParameters * @property {TextContent} textContent - Text content to render (the object is * returned by the page's getTextContent() method). * @property {HTMLElement} container - HTML element that will contain text runs. @@ -2118,17 +2445,17 @@ var renderTextLayer = (function renderTe function appendText(textDivs, viewport, geom, styles) { var style = styles[geom.fontName]; var textDiv = document.createElement('div'); textDivs.push(textDiv); if (isAllWhitespace(geom.str)) { textDiv.dataset.isWhitespace = true; return; } - var tx = PDFJS.Util.transform(viewport.transform, geom.transform); + var tx = Util.transform(viewport.transform, geom.transform); var angle = Math.atan2(tx[1], tx[0]); if (style.vertical) { angle += Math.PI / 2; } var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3])); var fontAscent = fontHeight; if (style.ascent) { fontAscent = style.ascent * fontAscent; @@ -2222,17 +2549,17 @@ var renderTextLayer = (function renderTe } else { transform = ''; } var rotation = textDiv.dataset.angle; if (rotation) { transform = 'rotate(' + rotation + 'deg) ' + transform; } if (transform) { - PDFJS.CustomStyle.setProp('transform' , textDiv, transform); + CustomStyle.setProp('transform' , textDiv, transform); } } } capability.resolve(); } /** * Text layer rendering task. @@ -4977,16 +5304,20 @@ var CanvasGraphics = (function CanvasGra this.ctx.drawImage(groupCtx.canvas, 0, 0); } this.restore(); }, beginAnnotations: function CanvasGraphics_beginAnnotations() { this.save(); this.current = new CanvasExtraState(); + + if (this.baseTransform) { + this.ctx.setTransform.apply(this.ctx, this.baseTransform); + } }, endAnnotations: function CanvasGraphics_endAnnotations() { this.restore(); }, beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform, matrix) { @@ -5395,16 +5726,18 @@ var FontFaceObject = displayFontLoader.F var FontLoader = displayFontLoader.FontLoader; var CanvasGraphics = displayCanvas.CanvasGraphics; var createScratchCanvas = displayCanvas.createScratchCanvas; var PDFJS = sharedGlobal.PDFJS; var globalScope = sharedGlobal.globalScope; var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536 + var fakeWorkerFilesLoader = null; + /** * The maximum allowed image size in total pixels e.g. width * height. Images * above this value will not be drawn. Use -1 for no limit. * @var {number} */ PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ? -1 : PDFJS.maxImageSize); @@ -5743,17 +6076,17 @@ PDFJS.getDocument = function getDocument if (task.destroyed) { throw new Error('Loading aborted'); } var messageHandler = new MessageHandler(docId, workerId, worker.port); messageHandler.send('Ready', null); var transport = new WorkerTransport(messageHandler, task, rangeTransport); task._transport = transport; }); - }, task._capability.reject); + }).catch(task._capability.reject); return task; }; /** * Starts fetching of specified PDF document/data. * @param {PDFWorker} worker * @param {Object} source @@ -6513,17 +6846,20 @@ var PDFWorker = (function PDFWorkerClosu // Loads worker code into main thread. function setupFakeWorkerGlobal() { if (!PDFJS.fakeWorkerFilesLoadedCapability) { PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability(); // In the developer build load worker_loader which in turn loads all the // other files and resolves the promise. In production only the // pdf.worker.js file is needed. - Util.loadScript(PDFJS.workerSrc, function() { + var loader = fakeWorkerFilesLoader || function (callback) { + Util.loadScript(PDFJS.workerSrc, callback); + }; + loader(function () { PDFJS.fakeWorkerFilesLoadedCapability.resolve(); }); } return PDFJS.fakeWorkerFilesLoadedCapability.promise; } function PDFWorker(name) { this.name = name; @@ -6561,17 +6897,16 @@ var PDFWorker = (function PDFWorkerClosu error('No PDFJS.workerSrc specified'); } try { // Some versions of FF can't create a worker on localhost, see: // https://bugzilla.mozilla.org/show_bug.cgi?id=683280 var worker = new Worker(workerSrc); var messageHandler = new MessageHandler('main', 'worker', worker); - messageHandler.on('test', function PDFWorker_test(data) { if (this.destroyed) { this._readyCapability.reject(new Error('Worker was destroyed')); messageHandler.destroy(); worker.terminate(); return; // worker was destroyed } var supportTypedArray = data && data.supportTypedArray; @@ -6592,39 +6927,65 @@ var PDFWorker = (function PDFWorkerClosu messageHandler.on('console_log', function (data) { console.log.apply(console, data); }); messageHandler.on('console_error', function (data) { console.error.apply(console, data); }); - var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]); - // Some versions of Opera throw a DATA_CLONE_ERR on serializing the - // typed array. Also, checking if we can use transfers. - try { - messageHandler.send('test', testObj, [testObj.buffer]); - } catch (ex) { - info('Cannot use postMessage transfers'); - testObj[0] = 0; - messageHandler.send('test', testObj); - } + messageHandler.on('ready', function (data) { + if (this.destroyed) { + this._readyCapability.reject(new Error('Worker was destroyed')); + messageHandler.destroy(); + worker.terminate(); + return; // worker was destroyed + } + try { + sendTest(); + } catch (e) { + // We need fallback to a faked worker. + this._setupFakeWorker(); + } + }.bind(this)); + + var sendTest = function () { + var testObj = new Uint8Array( + [PDFJS.postMessageTransfers ? 255 : 0]); + // Some versions of Opera throw a DATA_CLONE_ERR on serializing the + // typed array. Also, checking if we can use transfers. + try { + messageHandler.send('test', testObj, [testObj.buffer]); + } catch (ex) { + info('Cannot use postMessage transfers'); + testObj[0] = 0; + messageHandler.send('test', testObj); + } + }; + + // It might take time for worker to initialize (especially when AMD + // loader is used). We will try to send test immediately, and then + // when 'ready' message will arrive. The worker shall process only + // first received 'test'. + sendTest(); return; } catch (e) { info('The worker has been disabled.'); } } // Either workers are disabled, not supported or have thrown an exception. // Thus, we fallback to a faked worker. this._setupFakeWorker(); }, _setupFakeWorker: function PDFWorker_setupFakeWorker() { - warn('Setting up fake worker.'); - globalScope.PDFJS.disableWorker = true; + if (!globalScope.PDFJS.disableWorker) { + warn('Setting up fake worker.'); + globalScope.PDFJS.disableWorker = true; + } setupFakeWorkerGlobal().then(function () { if (this.destroyed) { this._readyCapability.reject(new Error('Worker was destroyed')); return; } // If we don't use a worker, just post/sendMessage to the main thread. @@ -7414,20 +7775,12 @@ PDFJS.UnsupportedManager = (function Uns exports.getDocument = PDFJS.getDocument; exports.PDFDataRangeTransport = PDFDataRangeTransport; exports.PDFDocumentProxy = PDFDocumentProxy; exports.PDFPageProxy = PDFPageProxy; })); -(function (root, factory) { - { - factory((root.pdfjsDisplaySVG = {}), root.pdfjsSharedUtil); - } -}(this, function (exports, sharedUtil) { -})); - - }).call((typeof window === 'undefined') ? this : window);
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -7,1409 +7,36 @@ * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ -/*jshint globalstrict: false */ -/* globals PDFJS */ +/* jshint globalstrict: false */ +/* globals PDFJS, global */ // Initializing PDFJS global object (if still undefined) if (typeof PDFJS === 'undefined') { - (typeof window !== 'undefined' ? window : this).PDFJS = {}; -} - -PDFJS.version = '1.3.110'; -PDFJS.build = '42beb0c'; + (typeof window !== 'undefined' ? window : + typeof global !== 'undefined' ? global : this).PDFJS = {}; +} + +PDFJS.version = '1.3.142'; +PDFJS.build = 'e8db825'; (function pdfjsWrapper() { // Use strict in our context only - users might not want it 'use strict'; (function (root, factory) { { - factory((root.pdfjsSharedGlobal = {})); - } -}(this, function (exports) { - - var globalScope = (typeof window !== 'undefined') ? window : - (typeof global !== 'undefined') ? global : - (typeof self !== 'undefined') ? self : this; - - var isWorker = (typeof window === 'undefined'); - - // The global PDFJS object exposes the API - // In production, it will be declared outside a global wrapper - // In development, it will be declared here - if (!globalScope.PDFJS) { - globalScope.PDFJS = {}; - } - - globalScope.PDFJS.pdfBug = false; - - exports.globalScope = globalScope; - exports.isWorker = isWorker; - exports.PDFJS = globalScope.PDFJS; -})); - - -(function (root, factory) { - { - factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedGlobal); - } -}(this, function (exports, sharedGlobal) { - -var PDFJS = sharedGlobal.PDFJS; -var globalScope = sharedGlobal.globalScope; - -var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; - -var TextRenderingMode = { - FILL: 0, - STROKE: 1, - FILL_STROKE: 2, - INVISIBLE: 3, - FILL_ADD_TO_PATH: 4, - STROKE_ADD_TO_PATH: 5, - FILL_STROKE_ADD_TO_PATH: 6, - ADD_TO_PATH: 7, - FILL_STROKE_MASK: 3, - ADD_TO_PATH_FLAG: 4 -}; - -var ImageKind = { - GRAYSCALE_1BPP: 1, - RGB_24BPP: 2, - RGBA_32BPP: 3 -}; - -var AnnotationType = { - TEXT: 1, - LINK: 2, - FREETEXT: 3, - LINE: 4, - SQUARE: 5, - CIRCLE: 6, - POLYGON: 7, - POLYLINE: 8, - HIGHLIGHT: 9, - UNDERLINE: 10, - SQUIGGLY: 11, - STRIKEOUT: 12, - STAMP: 13, - CARET: 14, - INK: 15, - POPUP: 16, - FILEATTACHMENT: 17, - SOUND: 18, - MOVIE: 19, - WIDGET: 20, - SCREEN: 21, - PRINTERMARK: 22, - TRAPNET: 23, - WATERMARK: 24, - THREED: 25, - REDACT: 26 -}; - -var AnnotationFlag = { - INVISIBLE: 0x01, - HIDDEN: 0x02, - PRINT: 0x04, - NOZOOM: 0x08, - NOROTATE: 0x10, - NOVIEW: 0x20, - READONLY: 0x40, - LOCKED: 0x80, - TOGGLENOVIEW: 0x100, - LOCKEDCONTENTS: 0x200 -}; - -var AnnotationBorderStyleType = { - SOLID: 1, - DASHED: 2, - BEVELED: 3, - INSET: 4, - UNDERLINE: 5 -}; - -var StreamType = { - UNKNOWN: 0, - FLATE: 1, - LZW: 2, - DCT: 3, - JPX: 4, - JBIG: 5, - A85: 6, - AHX: 7, - CCF: 8, - RL: 9 -}; - -var FontType = { - UNKNOWN: 0, - TYPE1: 1, - TYPE1C: 2, - CIDFONTTYPE0: 3, - CIDFONTTYPE0C: 4, - TRUETYPE: 5, - CIDFONTTYPE2: 6, - TYPE3: 7, - OPENTYPE: 8, - TYPE0: 9, - MMTYPE1: 10 -}; - -PDFJS.VERBOSITY_LEVELS = { - errors: 0, - warnings: 1, - infos: 5 -}; - -// All the possible operations for an operator list. -var OPS = PDFJS.OPS = { - // Intentionally start from 1 so it is easy to spot bad operators that will be - // 0's. - dependency: 1, - setLineWidth: 2, - setLineCap: 3, - setLineJoin: 4, - setMiterLimit: 5, - setDash: 6, - setRenderingIntent: 7, - setFlatness: 8, - setGState: 9, - save: 10, - restore: 11, - transform: 12, - moveTo: 13, - lineTo: 14, - curveTo: 15, - curveTo2: 16, - curveTo3: 17, - closePath: 18, - rectangle: 19, - stroke: 20, - closeStroke: 21, - fill: 22, - eoFill: 23, - fillStroke: 24, - eoFillStroke: 25, - closeFillStroke: 26, - closeEOFillStroke: 27, - endPath: 28, - clip: 29, - eoClip: 30, - beginText: 31, - endText: 32, - setCharSpacing: 33, - setWordSpacing: 34, - setHScale: 35, - setLeading: 36, - setFont: 37, - setTextRenderingMode: 38, - setTextRise: 39, - moveText: 40, - setLeadingMoveText: 41, - setTextMatrix: 42, - nextLine: 43, - showText: 44, - showSpacedText: 45, - nextLineShowText: 46, - nextLineSetSpacingShowText: 47, - setCharWidth: 48, - setCharWidthAndBounds: 49, - setStrokeColorSpace: 50, - setFillColorSpace: 51, - setStrokeColor: 52, - setStrokeColorN: 53, - setFillColor: 54, - setFillColorN: 55, - setStrokeGray: 56, - setFillGray: 57, - setStrokeRGBColor: 58, - setFillRGBColor: 59, - setStrokeCMYKColor: 60, - setFillCMYKColor: 61, - shadingFill: 62, - beginInlineImage: 63, - beginImageData: 64, - endInlineImage: 65, - paintXObject: 66, - markPoint: 67, - markPointProps: 68, - beginMarkedContent: 69, - beginMarkedContentProps: 70, - endMarkedContent: 71, - beginCompat: 72, - endCompat: 73, - paintFormXObjectBegin: 74, - paintFormXObjectEnd: 75, - beginGroup: 76, - endGroup: 77, - beginAnnotations: 78, - endAnnotations: 79, - beginAnnotation: 80, - endAnnotation: 81, - paintJpegXObject: 82, - paintImageMaskXObject: 83, - paintImageMaskXObjectGroup: 84, - paintImageXObject: 85, - paintInlineImageXObject: 86, - paintInlineImageXObjectGroup: 87, - paintImageXObjectRepeat: 88, - paintImageMaskXObjectRepeat: 89, - paintSolidColorImageMask: 90, - constructPath: 91 -}; - -// A notice for devs. These are good for things that are helpful to devs, such -// as warning that Workers were disabled, which is important to devs but not -// end users. -function info(msg) { - if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) { - console.log('Info: ' + msg); - } -} - -// Non-fatal warnings. -function warn(msg) { - if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) { - console.log('Warning: ' + msg); - } -} - -// Deprecated API function -- treated as warnings. -function deprecated(details) { - warn('Deprecated API usage: ' + details); -} - -// Fatal errors that should trigger the fallback UI and halt execution by -// throwing an exception. -function error(msg) { - if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) { - console.log('Error: ' + msg); - console.log(backtrace()); - } - throw new Error(msg); -} - -function backtrace() { - try { - throw new Error(); - } catch (e) { - return e.stack ? e.stack.split('\n').slice(2).join('\n') : ''; - } -} - -function assert(cond, msg) { - if (!cond) { - error(msg); - } -} - -var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = { - unknown: 'unknown', - forms: 'forms', - javaScript: 'javaScript', - smask: 'smask', - shadingPattern: 'shadingPattern', - font: 'font' -}; - -// Combines two URLs. The baseUrl shall be absolute URL. If the url is an -// absolute URL, it will be returned as is. -function combineUrl(baseUrl, url) { - if (!url) { - return baseUrl; - } - if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) { - return url; - } - var i; - if (url.charAt(0) === '/') { - // absolute path - i = baseUrl.indexOf('://'); - if (url.charAt(1) === '/') { - ++i; - } else { - i = baseUrl.indexOf('/', i + 3); - } - return baseUrl.substring(0, i) + url; - } else { - // relative path - var pathLength = baseUrl.length; - i = baseUrl.lastIndexOf('#'); - pathLength = i >= 0 ? i : pathLength; - i = baseUrl.lastIndexOf('?', pathLength); - pathLength = i >= 0 ? i : pathLength; - var prefixLength = baseUrl.lastIndexOf('/', pathLength); - return baseUrl.substring(0, prefixLength + 1) + url; - } -} - -// Validates if URL is safe and allowed, e.g. to avoid XSS. -function isValidUrl(url, allowRelative) { - if (!url) { - return false; - } - // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1) - // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url); - if (!protocol) { - return allowRelative; - } - protocol = protocol[0].toLowerCase(); - switch (protocol) { - case 'http': - case 'https': - case 'ftp': - case 'mailto': - case 'tel': - return true; - default: - return false; - } -} -PDFJS.isValidUrl = isValidUrl; - -function shadow(obj, prop, value) { - Object.defineProperty(obj, prop, { value: value, - enumerable: true, - configurable: true, - writable: false }); - return value; -} -PDFJS.shadow = shadow; - -var LinkTarget = PDFJS.LinkTarget = { - NONE: 0, // Default value. - SELF: 1, - BLANK: 2, - PARENT: 3, - TOP: 4, -}; -var LinkTargetStringMap = [ - '', - '_self', - '_blank', - '_parent', - '_top' -]; - -function isExternalLinkTargetSet() { - switch (PDFJS.externalLinkTarget) { - case LinkTarget.NONE: - return false; - case LinkTarget.SELF: - case LinkTarget.BLANK: - case LinkTarget.PARENT: - case LinkTarget.TOP: - return true; - } - warn('PDFJS.externalLinkTarget is invalid: ' + PDFJS.externalLinkTarget); - // Reset the external link target, to suppress further warnings. - PDFJS.externalLinkTarget = LinkTarget.NONE; - return false; -} -PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet; - -var PasswordResponses = PDFJS.PasswordResponses = { - NEED_PASSWORD: 1, - INCORRECT_PASSWORD: 2 -}; - -var PasswordException = (function PasswordExceptionClosure() { - function PasswordException(msg, code) { - this.name = 'PasswordException'; - this.message = msg; - this.code = code; - } - - PasswordException.prototype = new Error(); - PasswordException.constructor = PasswordException; - - return PasswordException; -})(); -PDFJS.PasswordException = PasswordException; - -var UnknownErrorException = (function UnknownErrorExceptionClosure() { - function UnknownErrorException(msg, details) { - this.name = 'UnknownErrorException'; - this.message = msg; - this.details = details; - } - - UnknownErrorException.prototype = new Error(); - UnknownErrorException.constructor = UnknownErrorException; - - return UnknownErrorException; -})(); -PDFJS.UnknownErrorException = UnknownErrorException; - -var InvalidPDFException = (function InvalidPDFExceptionClosure() { - function InvalidPDFException(msg) { - this.name = 'InvalidPDFException'; - this.message = msg; - } - - InvalidPDFException.prototype = new Error(); - InvalidPDFException.constructor = InvalidPDFException; - - return InvalidPDFException; -})(); -PDFJS.InvalidPDFException = InvalidPDFException; - -var MissingPDFException = (function MissingPDFExceptionClosure() { - function MissingPDFException(msg) { - this.name = 'MissingPDFException'; - this.message = msg; - } - - MissingPDFException.prototype = new Error(); - MissingPDFException.constructor = MissingPDFException; - - return MissingPDFException; -})(); -PDFJS.MissingPDFException = MissingPDFException; - -var UnexpectedResponseException = - (function UnexpectedResponseExceptionClosure() { - function UnexpectedResponseException(msg, status) { - this.name = 'UnexpectedResponseException'; - this.message = msg; - this.status = status; - } - - UnexpectedResponseException.prototype = new Error(); - UnexpectedResponseException.constructor = UnexpectedResponseException; - - return UnexpectedResponseException; -})(); -PDFJS.UnexpectedResponseException = UnexpectedResponseException; - -var NotImplementedException = (function NotImplementedExceptionClosure() { - function NotImplementedException(msg) { - this.message = msg; - } - - NotImplementedException.prototype = new Error(); - NotImplementedException.prototype.name = 'NotImplementedException'; - NotImplementedException.constructor = NotImplementedException; - - return NotImplementedException; -})(); - -var MissingDataException = (function MissingDataExceptionClosure() { - function MissingDataException(begin, end) { - this.begin = begin; - this.end = end; - this.message = 'Missing data [' + begin + ', ' + end + ')'; - } - - MissingDataException.prototype = new Error(); - MissingDataException.prototype.name = 'MissingDataException'; - MissingDataException.constructor = MissingDataException; - - return MissingDataException; -})(); - -var XRefParseException = (function XRefParseExceptionClosure() { - function XRefParseException(msg) { - this.message = msg; - } - - XRefParseException.prototype = new Error(); - XRefParseException.prototype.name = 'XRefParseException'; - XRefParseException.constructor = XRefParseException; - - return XRefParseException; -})(); - - -function bytesToString(bytes) { - assert(bytes !== null && typeof bytes === 'object' && - bytes.length !== undefined, 'Invalid argument for bytesToString'); - var length = bytes.length; - var MAX_ARGUMENT_COUNT = 8192; - if (length < MAX_ARGUMENT_COUNT) { - return String.fromCharCode.apply(null, bytes); - } - var strBuf = []; - for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { - var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); - var chunk = bytes.subarray(i, chunkEnd); - strBuf.push(String.fromCharCode.apply(null, chunk)); - } - return strBuf.join(''); -} - -function stringToBytes(str) { - assert(typeof str === 'string', 'Invalid argument for stringToBytes'); - var length = str.length; - var bytes = new Uint8Array(length); - for (var i = 0; i < length; ++i) { - bytes[i] = str.charCodeAt(i) & 0xFF; - } - return bytes; -} - -function string32(value) { - return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff, - (value >> 8) & 0xff, value & 0xff); -} - -function log2(x) { - var n = 1, i = 0; - while (x > n) { - n <<= 1; - i++; - } - return i; -} - -function readInt8(data, start) { - return (data[start] << 24) >> 24; -} - -function readUint16(data, offset) { - return (data[offset] << 8) | data[offset + 1]; -} - -function readUint32(data, offset) { - return ((data[offset] << 24) | (data[offset + 1] << 16) | - (data[offset + 2] << 8) | data[offset + 3]) >>> 0; -} - -// Lazy test the endianness of the platform -// NOTE: This will be 'true' for simulated TypedArrays -function isLittleEndian() { - var buffer8 = new Uint8Array(2); - buffer8[0] = 1; - var buffer16 = new Uint16Array(buffer8.buffer); - return (buffer16[0] === 1); -} - -Object.defineProperty(PDFJS, 'isLittleEndian', { - configurable: true, - get: function PDFJS_isLittleEndian() { - return shadow(PDFJS, 'isLittleEndian', isLittleEndian()); - } -}); - - PDFJS.hasCanvasTypedArrays = true; - -var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; - -var Util = PDFJS.Util = (function UtilClosure() { - function Util() {} - - var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; - - // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids - // creating many intermediate strings. - Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { - rgbBuf[1] = r; - rgbBuf[3] = g; - rgbBuf[5] = b; - return rgbBuf.join(''); - }; - - // Concatenates two transformation matrices together and returns the result. - Util.transform = function Util_transform(m1, m2) { - return [ - m1[0] * m2[0] + m1[2] * m2[1], - m1[1] * m2[0] + m1[3] * m2[1], - m1[0] * m2[2] + m1[2] * m2[3], - m1[1] * m2[2] + m1[3] * m2[3], - m1[0] * m2[4] + m1[2] * m2[5] + m1[4], - m1[1] * m2[4] + m1[3] * m2[5] + m1[5] - ]; - }; - - // For 2d affine transforms - Util.applyTransform = function Util_applyTransform(p, m) { - var xt = p[0] * m[0] + p[1] * m[2] + m[4]; - var yt = p[0] * m[1] + p[1] * m[3] + m[5]; - return [xt, yt]; - }; - - Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { - var d = m[0] * m[3] - m[1] * m[2]; - var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; - var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; - return [xt, yt]; - }; - - // Applies the transform to the rectangle and finds the minimum axially - // aligned bounding box. - Util.getAxialAlignedBoundingBox = - function Util_getAxialAlignedBoundingBox(r, m) { - - var p1 = Util.applyTransform(r, m); - var p2 = Util.applyTransform(r.slice(2, 4), m); - var p3 = Util.applyTransform([r[0], r[3]], m); - var p4 = Util.applyTransform([r[2], r[1]], m); - return [ - Math.min(p1[0], p2[0], p3[0], p4[0]), - Math.min(p1[1], p2[1], p3[1], p4[1]), - Math.max(p1[0], p2[0], p3[0], p4[0]), - Math.max(p1[1], p2[1], p3[1], p4[1]) - ]; - }; - - Util.inverseTransform = function Util_inverseTransform(m) { - var d = m[0] * m[3] - m[1] * m[2]; - return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, - (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; - }; - - // Apply a generic 3d matrix M on a 3-vector v: - // | a b c | | X | - // | d e f | x | Y | - // | g h i | | Z | - // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i], - // with v as [X,Y,Z] - Util.apply3dTransform = function Util_apply3dTransform(m, v) { - return [ - m[0] * v[0] + m[1] * v[1] + m[2] * v[2], - m[3] * v[0] + m[4] * v[1] + m[5] * v[2], - m[6] * v[0] + m[7] * v[1] + m[8] * v[2] - ]; - }; - - // This calculation uses Singular Value Decomposition. - // The SVD can be represented with formula A = USV. We are interested in the - // matrix S here because it represents the scale values. - Util.singularValueDecompose2dScale = - function Util_singularValueDecompose2dScale(m) { - - var transpose = [m[0], m[2], m[1], m[3]]; - - // Multiply matrix m with its transpose. - var a = m[0] * transpose[0] + m[1] * transpose[2]; - var b = m[0] * transpose[1] + m[1] * transpose[3]; - var c = m[2] * transpose[0] + m[3] * transpose[2]; - var d = m[2] * transpose[1] + m[3] * transpose[3]; - - // Solve the second degree polynomial to get roots. - var first = (a + d) / 2; - var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; - var sx = first + second || 1; - var sy = first - second || 1; - - // Scale values are the square roots of the eigenvalues. - return [Math.sqrt(sx), Math.sqrt(sy)]; - }; - - // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2) - // For coordinate systems whose origin lies in the bottom-left, this - // means normalization to (BL,TR) ordering. For systems with origin in the - // top-left, this means (TL,BR) ordering. - Util.normalizeRect = function Util_normalizeRect(rect) { - var r = rect.slice(0); // clone rect - if (rect[0] > rect[2]) { - r[0] = rect[2]; - r[2] = rect[0]; - } - if (rect[1] > rect[3]) { - r[1] = rect[3]; - r[3] = rect[1]; - } - return r; - }; - - // Returns a rectangle [x1, y1, x2, y2] corresponding to the - // intersection of rect1 and rect2. If no intersection, returns 'false' - // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] - Util.intersect = function Util_intersect(rect1, rect2) { - function compare(a, b) { - return a - b; - } - - // Order points along the axes - var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), - orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), - result = []; - - rect1 = Util.normalizeRect(rect1); - rect2 = Util.normalizeRect(rect2); - - // X: first and second points belong to different rectangles? - if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) || - (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) { - // Intersection must be between second and third points - result[0] = orderedX[1]; - result[2] = orderedX[2]; - } else { - return false; - } - - // Y: first and second points belong to different rectangles? - if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) || - (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) { - // Intersection must be between second and third points - result[1] = orderedY[1]; - result[3] = orderedY[2]; - } else { - return false; - } - - return result; - }; - - Util.sign = function Util_sign(num) { - return num < 0 ? -1 : 1; - }; - - Util.appendToArray = function Util_appendToArray(arr1, arr2) { - Array.prototype.push.apply(arr1, arr2); - }; - - Util.prependToArray = function Util_prependToArray(arr1, arr2) { - Array.prototype.unshift.apply(arr1, arr2); - }; - - Util.extendObj = function extendObj(obj1, obj2) { - for (var key in obj2) { - obj1[key] = obj2[key]; - } - }; - - Util.getInheritableProperty = function Util_getInheritableProperty(dict, - name) { - while (dict && !dict.has(name)) { - dict = dict.get('Parent'); - } - if (!dict) { - return null; - } - return dict.get(name); - }; - - Util.inherit = function Util_inherit(sub, base, prototype) { - sub.prototype = Object.create(base.prototype); - sub.prototype.constructor = sub; - for (var prop in prototype) { - sub.prototype[prop] = prototype[prop]; - } - }; - - Util.loadScript = function Util_loadScript(src, callback) { - var script = document.createElement('script'); - var loaded = false; - script.setAttribute('src', src); - if (callback) { - script.onload = function() { - if (!loaded) { - callback(); - } - loaded = true; - }; - } - document.getElementsByTagName('head')[0].appendChild(script); - }; - - return Util; -})(); - -/** - * PDF page viewport created based on scale, rotation and offset. - * @class - * @alias PDFJS.PageViewport - */ -var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() { - /** - * @constructor - * @private - * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates. - * @param scale {number} scale of the viewport. - * @param rotation {number} rotations of the viewport in degrees. - * @param offsetX {number} offset X - * @param offsetY {number} offset Y - * @param dontFlip {boolean} if true, axis Y will not be flipped. - */ - function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) { - this.viewBox = viewBox; - this.scale = scale; - this.rotation = rotation; - this.offsetX = offsetX; - this.offsetY = offsetY; - - // creating transform to convert pdf coordinate system to the normal - // canvas like coordinates taking in account scale and rotation - var centerX = (viewBox[2] + viewBox[0]) / 2; - var centerY = (viewBox[3] + viewBox[1]) / 2; - var rotateA, rotateB, rotateC, rotateD; - rotation = rotation % 360; - rotation = rotation < 0 ? rotation + 360 : rotation; - switch (rotation) { - case 180: - rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1; - break; - case 90: - rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0; - break; - case 270: - rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0; - break; - //case 0: - default: - rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1; - break; - } - - if (dontFlip) { - rotateC = -rotateC; rotateD = -rotateD; - } - - var offsetCanvasX, offsetCanvasY; - var width, height; - if (rotateA === 0) { - offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; - offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; - width = Math.abs(viewBox[3] - viewBox[1]) * scale; - height = Math.abs(viewBox[2] - viewBox[0]) * scale; - } else { - offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; - offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; - width = Math.abs(viewBox[2] - viewBox[0]) * scale; - height = Math.abs(viewBox[3] - viewBox[1]) * scale; - } - // creating transform for the following operations: - // translate(-centerX, -centerY), rotate and flip vertically, - // scale, and translate(offsetCanvasX, offsetCanvasY) - this.transform = [ - rotateA * scale, - rotateB * scale, - rotateC * scale, - rotateD * scale, - offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, - offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY - ]; - - this.width = width; - this.height = height; - this.fontScale = scale; - } - PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ { - /** - * Clones viewport with additional properties. - * @param args {Object} (optional) If specified, may contain the 'scale' or - * 'rotation' properties to override the corresponding properties in - * the cloned viewport. - * @returns {PDFJS.PageViewport} Cloned viewport. - */ - clone: function PageViewPort_clone(args) { - args = args || {}; - var scale = 'scale' in args ? args.scale : this.scale; - var rotation = 'rotation' in args ? args.rotation : this.rotation; - return new PageViewport(this.viewBox.slice(), scale, rotation, - this.offsetX, this.offsetY, args.dontFlip); - }, - /** - * Converts PDF point to the viewport coordinates. For examples, useful for - * converting PDF location into canvas pixel coordinates. - * @param x {number} X coordinate. - * @param y {number} Y coordinate. - * @returns {Object} Object that contains 'x' and 'y' properties of the - * point in the viewport coordinate space. - * @see {@link convertToPdfPoint} - * @see {@link convertToViewportRectangle} - */ - convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) { - return Util.applyTransform([x, y], this.transform); - }, - /** - * Converts PDF rectangle to the viewport coordinates. - * @param rect {Array} xMin, yMin, xMax and yMax coordinates. - * @returns {Array} Contains corresponding coordinates of the rectangle - * in the viewport coordinate space. - * @see {@link convertToViewportPoint} - */ - convertToViewportRectangle: - function PageViewport_convertToViewportRectangle(rect) { - var tl = Util.applyTransform([rect[0], rect[1]], this.transform); - var br = Util.applyTransform([rect[2], rect[3]], this.transform); - return [tl[0], tl[1], br[0], br[1]]; - }, - /** - * Converts viewport coordinates to the PDF location. For examples, useful - * for converting canvas pixel location into PDF one. - * @param x {number} X coordinate. - * @param y {number} Y coordinate. - * @returns {Object} Object that contains 'x' and 'y' properties of the - * point in the PDF coordinate space. - * @see {@link convertToViewportPoint} - */ - convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) { - return Util.applyInverseTransform([x, y], this.transform); - } - }; - return PageViewport; -})(); - -var PDFStringTranslateTable = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, - 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, - 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, - 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC -]; - -function stringToPDFString(str) { - var i, n = str.length, strBuf = []; - if (str[0] === '\xFE' && str[1] === '\xFF') { - // UTF16BE BOM - for (i = 2; i < n; i += 2) { - strBuf.push(String.fromCharCode( - (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))); - } - } else { - for (i = 0; i < n; ++i) { - var code = PDFStringTranslateTable[str.charCodeAt(i)]; - strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); - } - } - return strBuf.join(''); -} - -function stringToUTF8String(str) { - return decodeURIComponent(escape(str)); -} - -function utf8StringToString(str) { - return unescape(encodeURIComponent(str)); -} - -function isEmptyObj(obj) { - for (var key in obj) { - return false; - } - return true; -} - -function isBool(v) { - return typeof v === 'boolean'; -} - -function isInt(v) { - return typeof v === 'number' && ((v | 0) === v); -} - -function isNum(v) { - return typeof v === 'number'; -} - -function isString(v) { - return typeof v === 'string'; -} - -function isArray(v) { - return v instanceof Array; -} - -function isArrayBuffer(v) { - return typeof v === 'object' && v !== null && v.byteLength !== undefined; -} - -/** - * Promise Capability object. - * - * @typedef {Object} PromiseCapability - * @property {Promise} promise - A promise object. - * @property {function} resolve - Fullfills the promise. - * @property {function} reject - Rejects the promise. - */ - -/** - * Creates a promise capability object. - * @alias PDFJS.createPromiseCapability - * - * @return {PromiseCapability} A capability object contains: - * - a Promise, resolve and reject methods. - */ -function createPromiseCapability() { - var capability = {}; - capability.promise = new Promise(function (resolve, reject) { - capability.resolve = resolve; - capability.reject = reject; - }); - return capability; -} - -PDFJS.createPromiseCapability = createPromiseCapability; - -/** - * Polyfill for Promises: - * The following promise implementation tries to generally implement the - * Promise/A+ spec. Some notable differences from other promise libaries are: - * - There currently isn't a seperate deferred and promise object. - * - Unhandled rejections eventually show an error if they aren't handled. - * - * Based off of the work in: - * https://bugzilla.mozilla.org/show_bug.cgi?id=810490 - */ -(function PromiseClosure() { - if (globalScope.Promise) { - // Promises existing in the DOM/Worker, checking presence of all/resolve - if (typeof globalScope.Promise.all !== 'function') { - globalScope.Promise.all = function (iterable) { - var count = 0, results = [], resolve, reject; - var promise = new globalScope.Promise(function (resolve_, reject_) { - resolve = resolve_; - reject = reject_; - }); - iterable.forEach(function (p, i) { - count++; - p.then(function (result) { - results[i] = result; - count--; - if (count === 0) { - resolve(results); - } - }, reject); - }); - if (count === 0) { - resolve(results); - } - return promise; - }; - } - if (typeof globalScope.Promise.resolve !== 'function') { - globalScope.Promise.resolve = function (value) { - return new globalScope.Promise(function (resolve) { resolve(value); }); - }; - } - if (typeof globalScope.Promise.reject !== 'function') { - globalScope.Promise.reject = function (reason) { - return new globalScope.Promise(function (resolve, reject) { - reject(reason); - }); - }; - } - if (typeof globalScope.Promise.prototype.catch !== 'function') { - globalScope.Promise.prototype.catch = function (onReject) { - return globalScope.Promise.prototype.then(undefined, onReject); - }; - } - return; - } - throw new Error('DOM Promise is not present'); -})(); - -var StatTimer = (function StatTimerClosure() { - function rpad(str, pad, length) { - while (str.length < length) { - str += pad; - } - return str; - } - function StatTimer() { - this.started = {}; - this.times = []; - this.enabled = true; - } - StatTimer.prototype = { - time: function StatTimer_time(name) { - if (!this.enabled) { - return; - } - if (name in this.started) { - warn('Timer is already running for ' + name); - } - this.started[name] = Date.now(); - }, - timeEnd: function StatTimer_timeEnd(name) { - if (!this.enabled) { - return; - } - if (!(name in this.started)) { - warn('Timer has not been started for ' + name); - } - this.times.push({ - 'name': name, - 'start': this.started[name], - 'end': Date.now() - }); - // Remove timer from started so it can be called again. - delete this.started[name]; - }, - toString: function StatTimer_toString() { - var i, ii; - var times = this.times; - var out = ''; - // Find the longest name for padding purposes. - var longest = 0; - for (i = 0, ii = times.length; i < ii; ++i) { - var name = times[i]['name']; - if (name.length > longest) { - longest = name.length; - } - } - for (i = 0, ii = times.length; i < ii; ++i) { - var span = times[i]; - var duration = span.end - span.start; - out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n'; - } - return out; - } - }; - return StatTimer; -})(); - -PDFJS.createBlob = function createBlob(data, contentType) { - if (typeof Blob !== 'undefined') { - return new Blob([data], { type: contentType }); - } - // Blob builder is deprecated in FF14 and removed in FF18. - var bb = new MozBlobBuilder(); - bb.append(data); - return bb.getBlob(contentType); -}; - -PDFJS.createObjectURL = (function createObjectURLClosure() { - // Blob/createObjectURL is not available, falling back to data schema. - var digits = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - - return function createObjectURL(data, contentType) { - if (!PDFJS.disableCreateObjectURL && - typeof URL !== 'undefined' && URL.createObjectURL) { - var blob = PDFJS.createBlob(data, contentType); - return URL.createObjectURL(blob); - } - - var buffer = 'data:' + contentType + ';base64,'; - for (var i = 0, ii = data.length; i < ii; i += 3) { - var b1 = data[i] & 0xFF; - var b2 = data[i + 1] & 0xFF; - var b3 = data[i + 2] & 0xFF; - var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); - var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; - var d4 = i + 2 < ii ? (b3 & 0x3F) : 64; - buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; - } - return buffer; - }; -})(); - -function MessageHandler(sourceName, targetName, comObj) { - this.sourceName = sourceName; - this.targetName = targetName; - this.comObj = comObj; - this.callbackIndex = 1; - this.postMessageTransfers = true; - var callbacksCapabilities = this.callbacksCapabilities = {}; - var ah = this.actionHandler = {}; - - this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) { - var data = event.data; - if (data.targetName !== this.sourceName) { - return; - } - if (data.isReply) { - var callbackId = data.callbackId; - if (data.callbackId in callbacksCapabilities) { - var callback = callbacksCapabilities[callbackId]; - delete callbacksCapabilities[callbackId]; - if ('error' in data) { - callback.reject(data.error); - } else { - callback.resolve(data.data); - } - } else { - error('Cannot resolve callback ' + callbackId); - } - } else if (data.action in ah) { - var action = ah[data.action]; - if (data.callbackId) { - var sourceName = this.sourceName; - var targetName = data.sourceName; - Promise.resolve().then(function () { - return action[0].call(action[1], data.data); - }).then(function (result) { - comObj.postMessage({ - sourceName: sourceName, - targetName: targetName, - isReply: true, - callbackId: data.callbackId, - data: result - }); - }, function (reason) { - if (reason instanceof Error) { - // Serialize error to avoid "DataCloneError" - reason = reason + ''; - } - comObj.postMessage({ - sourceName: sourceName, - targetName: targetName, - isReply: true, - callbackId: data.callbackId, - error: reason - }); - }); - } else { - action[0].call(action[1], data.data); - } - } else { - error('Unknown action from worker: ' + data.action); - } - }.bind(this); - comObj.addEventListener('message', this._onComObjOnMessage); -} - -MessageHandler.prototype = { - on: function messageHandlerOn(actionName, handler, scope) { - var ah = this.actionHandler; - if (ah[actionName]) { - error('There is already an actionName called "' + actionName + '"'); - } - ah[actionName] = [handler, scope]; - }, - /** - * Sends a message to the comObj to invoke the action with the supplied data. - * @param {String} actionName Action to call. - * @param {JSON} data JSON data to send. - * @param {Array} [transfers] Optional list of transfers/ArrayBuffers - */ - send: function messageHandlerSend(actionName, data, transfers) { - var message = { - sourceName: this.sourceName, - targetName: this.targetName, - action: actionName, - data: data - }; - this.postMessage(message, transfers); - }, - /** - * Sends a message to the comObj to invoke the action with the supplied data. - * Expects that other side will callback with the response. - * @param {String} actionName Action to call. - * @param {JSON} data JSON data to send. - * @param {Array} [transfers] Optional list of transfers/ArrayBuffers. - * @returns {Promise} Promise to be resolved with response data. - */ - sendWithPromise: - function messageHandlerSendWithPromise(actionName, data, transfers) { - var callbackId = this.callbackIndex++; - var message = { - sourceName: this.sourceName, - targetName: this.targetName, - action: actionName, - data: data, - callbackId: callbackId - }; - var capability = createPromiseCapability(); - this.callbacksCapabilities[callbackId] = capability; - try { - this.postMessage(message, transfers); - } catch (e) { - capability.reject(e); - } - return capability.promise; - }, - /** - * Sends raw message to the comObj. - * @private - * @param message {Object} Raw message. - * @param transfers List of transfers/ArrayBuffers, or undefined. - */ - postMessage: function (message, transfers) { - if (transfers && this.postMessageTransfers) { - this.comObj.postMessage(message, transfers); - } else { - this.comObj.postMessage(message); - } - }, - - destroy: function () { - this.comObj.removeEventListener('message', this._onComObjOnMessage); - } -}; - -function loadJpegStream(id, imageUrl, objs) { - var img = new Image(); - img.onload = (function loadJpegStream_onloadClosure() { - objs.resolve(id, img); - }); - img.onerror = (function loadJpegStream_onerrorClosure() { - objs.resolve(id, null); - warn('Error during JPEG image loading'); - }); - img.src = imageUrl; -} - -exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; -exports.IDENTITY_MATRIX = IDENTITY_MATRIX; -exports.OPS = OPS; -exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; -exports.AnnotationBorderStyleType = AnnotationBorderStyleType; -exports.AnnotationFlag = AnnotationFlag; -exports.AnnotationType = AnnotationType; -exports.FontType = FontType; -exports.ImageKind = ImageKind; -exports.InvalidPDFException = InvalidPDFException; -exports.LinkTarget = LinkTarget; -exports.LinkTargetStringMap = LinkTargetStringMap; -exports.MessageHandler = MessageHandler; -exports.MissingDataException = MissingDataException; -exports.MissingPDFException = MissingPDFException; -exports.NotImplementedException = NotImplementedException; -exports.PasswordException = PasswordException; -exports.PasswordResponses = PasswordResponses; -exports.StatTimer = StatTimer; -exports.StreamType = StreamType; -exports.TextRenderingMode = TextRenderingMode; -exports.UnexpectedResponseException = UnexpectedResponseException; -exports.UnknownErrorException = UnknownErrorException; -exports.Util = Util; -exports.XRefParseException = XRefParseException; -exports.assert = assert; -exports.bytesToString = bytesToString; -exports.combineUrl = combineUrl; -exports.createPromiseCapability = createPromiseCapability; -exports.deprecated = deprecated; -exports.error = error; -exports.info = info; -exports.isArray = isArray; -exports.isArrayBuffer = isArrayBuffer; -exports.isBool = isBool; -exports.isEmptyObj = isEmptyObj; -exports.isExternalLinkTargetSet = isExternalLinkTargetSet; -exports.isInt = isInt; -exports.isNum = isNum; -exports.isString = isString; -exports.isValidUrl = isValidUrl; -exports.loadJpegStream = loadJpegStream; -exports.log2 = log2; -exports.readInt8 = readInt8; -exports.readUint16 = readUint16; -exports.readUint32 = readUint32; -exports.shadow = shadow; -exports.string32 = string32; -exports.stringToBytes = stringToBytes; -exports.stringToPDFString = stringToPDFString; -exports.stringToUTF8String = stringToUTF8String; -exports.utf8StringToString = utf8StringToString; -exports.warn = warn; -})); - - -(function (root, factory) { - { factory((root.pdfjsCoreArithmeticDecoder = {})); } }(this, function (exports) { /* This class implements the QM Coder decoding as defined in * JPEG 2000 Part I Final Committee Draft Version 1.0 * Annex C.3 Arithmetic decoding procedure * available at http://www.jpeg.org/public/fcd15444-1.pdf @@ -10089,16 +8716,43 @@ var Metrics = { }; exports.Metrics = Metrics; })); (function (root, factory) { { + factory((root.pdfjsSharedGlobal = {})); + } +}(this, function (exports) { + + var globalScope = (typeof window !== 'undefined') ? window : + (typeof global !== 'undefined') ? global : + (typeof self !== 'undefined') ? self : this; + + var isWorker = (typeof window === 'undefined'); + + // The global PDFJS object exposes the API + // In production, it will be declared outside a global wrapper + // In development, it will be declared here + if (!globalScope.PDFJS) { + globalScope.PDFJS = {}; + } + + globalScope.PDFJS.pdfBug = false; + + exports.globalScope = globalScope; + exports.isWorker = isWorker; + exports.PDFJS = globalScope.PDFJS; +})); + + +(function (root, factory) { + { factory((root.pdfjsCoreBidi = {}), root.pdfjsSharedGlobal); } }(this, function (exports, sharedGlobal) { var PDFJS = sharedGlobal.PDFJS; var bidi = PDFJS.bidi = (function bidiClosure() { // Character types for symbols from 0000 to 00FF. @@ -10507,16 +9161,1363 @@ var bidi = PDFJS.bidi = (function bidiCl })(); exports.bidi = bidi; })); (function (root, factory) { { + factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedGlobal); + } +}(this, function (exports, sharedGlobal) { + +var PDFJS = sharedGlobal.PDFJS; +var globalScope = sharedGlobal.globalScope; + +var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0]; + +var TextRenderingMode = { + FILL: 0, + STROKE: 1, + FILL_STROKE: 2, + INVISIBLE: 3, + FILL_ADD_TO_PATH: 4, + STROKE_ADD_TO_PATH: 5, + FILL_STROKE_ADD_TO_PATH: 6, + ADD_TO_PATH: 7, + FILL_STROKE_MASK: 3, + ADD_TO_PATH_FLAG: 4 +}; + +var ImageKind = { + GRAYSCALE_1BPP: 1, + RGB_24BPP: 2, + RGBA_32BPP: 3 +}; + +var AnnotationType = { + TEXT: 1, + LINK: 2, + FREETEXT: 3, + LINE: 4, + SQUARE: 5, + CIRCLE: 6, + POLYGON: 7, + POLYLINE: 8, + HIGHLIGHT: 9, + UNDERLINE: 10, + SQUIGGLY: 11, + STRIKEOUT: 12, + STAMP: 13, + CARET: 14, + INK: 15, + POPUP: 16, + FILEATTACHMENT: 17, + SOUND: 18, + MOVIE: 19, + WIDGET: 20, + SCREEN: 21, + PRINTERMARK: 22, + TRAPNET: 23, + WATERMARK: 24, + THREED: 25, + REDACT: 26 +}; + +var AnnotationFlag = { + INVISIBLE: 0x01, + HIDDEN: 0x02, + PRINT: 0x04, + NOZOOM: 0x08, + NOROTATE: 0x10, + NOVIEW: 0x20, + READONLY: 0x40, + LOCKED: 0x80, + TOGGLENOVIEW: 0x100, + LOCKEDCONTENTS: 0x200 +}; + +var AnnotationBorderStyleType = { + SOLID: 1, + DASHED: 2, + BEVELED: 3, + INSET: 4, + UNDERLINE: 5 +}; + +var StreamType = { + UNKNOWN: 0, + FLATE: 1, + LZW: 2, + DCT: 3, + JPX: 4, + JBIG: 5, + A85: 6, + AHX: 7, + CCF: 8, + RL: 9 +}; + +var FontType = { + UNKNOWN: 0, + TYPE1: 1, + TYPE1C: 2, + CIDFONTTYPE0: 3, + CIDFONTTYPE0C: 4, + TRUETYPE: 5, + CIDFONTTYPE2: 6, + TYPE3: 7, + OPENTYPE: 8, + TYPE0: 9, + MMTYPE1: 10 +}; + +PDFJS.VERBOSITY_LEVELS = { + errors: 0, + warnings: 1, + infos: 5 +}; + +// All the possible operations for an operator list. +var OPS = PDFJS.OPS = { + // Intentionally start from 1 so it is easy to spot bad operators that will be + // 0's. + dependency: 1, + setLineWidth: 2, + setLineCap: 3, + setLineJoin: 4, + setMiterLimit: 5, + setDash: 6, + setRenderingIntent: 7, + setFlatness: 8, + setGState: 9, + save: 10, + restore: 11, + transform: 12, + moveTo: 13, + lineTo: 14, + curveTo: 15, + curveTo2: 16, + curveTo3: 17, + closePath: 18, + rectangle: 19, + stroke: 20, + closeStroke: 21, + fill: 22, + eoFill: 23, + fillStroke: 24, + eoFillStroke: 25, + closeFillStroke: 26, + closeEOFillStroke: 27, + endPath: 28, + clip: 29, + eoClip: 30, + beginText: 31, + endText: 32, + setCharSpacing: 33, + setWordSpacing: 34, + setHScale: 35, + setLeading: 36, + setFont: 37, + setTextRenderingMode: 38, + setTextRise: 39, + moveText: 40, + setLeadingMoveText: 41, + setTextMatrix: 42, + nextLine: 43, + showText: 44, + showSpacedText: 45, + nextLineShowText: 46, + nextLineSetSpacingShowText: 47, + setCharWidth: 48, + setCharWidthAndBounds: 49, + setStrokeColorSpace: 50, + setFillColorSpace: 51, + setStrokeColor: 52, + setStrokeColorN: 53, + setFillColor: 54, + setFillColorN: 55, + setStrokeGray: 56, + setFillGray: 57, + setStrokeRGBColor: 58, + setFillRGBColor: 59, + setStrokeCMYKColor: 60, + setFillCMYKColor: 61, + shadingFill: 62, + beginInlineImage: 63, + beginImageData: 64, + endInlineImage: 65, + paintXObject: 66, + markPoint: 67, + markPointProps: 68, + beginMarkedContent: 69, + beginMarkedContentProps: 70, + endMarkedContent: 71, + beginCompat: 72, + endCompat: 73, + paintFormXObjectBegin: 74, + paintFormXObjectEnd: 75, + beginGroup: 76, + endGroup: 77, + beginAnnotations: 78, + endAnnotations: 79, + beginAnnotation: 80, + endAnnotation: 81, + paintJpegXObject: 82, + paintImageMaskXObject: 83, + paintImageMaskXObjectGroup: 84, + paintImageXObject: 85, + paintInlineImageXObject: 86, + paintInlineImageXObjectGroup: 87, + paintImageXObjectRepeat: 88, + paintImageMaskXObjectRepeat: 89, + paintSolidColorImageMask: 90, + constructPath: 91 +}; + +// A notice for devs. These are good for things that are helpful to devs, such +// as warning that Workers were disabled, which is important to devs but not +// end users. +function info(msg) { + if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) { + console.log('Info: ' + msg); + } +} + +// Non-fatal warnings. +function warn(msg) { + if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) { + console.log('Warning: ' + msg); + } +} + +// Deprecated API function -- treated as warnings. +function deprecated(details) { + warn('Deprecated API usage: ' + details); +} + +// Fatal errors that should trigger the fallback UI and halt execution by +// throwing an exception. +function error(msg) { + if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) { + console.log('Error: ' + msg); + console.log(backtrace()); + } + throw new Error(msg); +} + +function backtrace() { + try { + throw new Error(); + } catch (e) { + return e.stack ? e.stack.split('\n').slice(2).join('\n') : ''; + } +} + +function assert(cond, msg) { + if (!cond) { + error(msg); + } +} + +var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = { + unknown: 'unknown', + forms: 'forms', + javaScript: 'javaScript', + smask: 'smask', + shadingPattern: 'shadingPattern', + font: 'font' +}; + +// Combines two URLs. The baseUrl shall be absolute URL. If the url is an +// absolute URL, it will be returned as is. +function combineUrl(baseUrl, url) { + if (!url) { + return baseUrl; + } + if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) { + return url; + } + var i; + if (url.charAt(0) === '/') { + // absolute path + i = baseUrl.indexOf('://'); + if (url.charAt(1) === '/') { + ++i; + } else { + i = baseUrl.indexOf('/', i + 3); + } + return baseUrl.substring(0, i) + url; + } else { + // relative path + var pathLength = baseUrl.length; + i = baseUrl.lastIndexOf('#'); + pathLength = i >= 0 ? i : pathLength; + i = baseUrl.lastIndexOf('?', pathLength); + pathLength = i >= 0 ? i : pathLength; + var prefixLength = baseUrl.lastIndexOf('/', pathLength); + return baseUrl.substring(0, prefixLength + 1) + url; + } +} + +// Validates if URL is safe and allowed, e.g. to avoid XSS. +function isValidUrl(url, allowRelative) { + if (!url) { + return false; + } + // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1) + // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url); + if (!protocol) { + return allowRelative; + } + protocol = protocol[0].toLowerCase(); + switch (protocol) { + case 'http': + case 'https': + case 'ftp': + case 'mailto': + case 'tel': + return true; + default: + return false; + } +} +PDFJS.isValidUrl = isValidUrl; + +function shadow(obj, prop, value) { + Object.defineProperty(obj, prop, { value: value, + enumerable: true, + configurable: true, + writable: false }); + return value; +} +PDFJS.shadow = shadow; + +var LinkTarget = PDFJS.LinkTarget = { + NONE: 0, // Default value. + SELF: 1, + BLANK: 2, + PARENT: 3, + TOP: 4, +}; +var LinkTargetStringMap = [ + '', + '_self', + '_blank', + '_parent', + '_top' +]; + +function isExternalLinkTargetSet() { + switch (PDFJS.externalLinkTarget) { + case LinkTarget.NONE: + return false; + case LinkTarget.SELF: + case LinkTarget.BLANK: + case LinkTarget.PARENT: + case LinkTarget.TOP: + return true; + } + warn('PDFJS.externalLinkTarget is invalid: ' + PDFJS.externalLinkTarget); + // Reset the external link target, to suppress further warnings. + PDFJS.externalLinkTarget = LinkTarget.NONE; + return false; +} +PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet; + +var PasswordResponses = PDFJS.PasswordResponses = { + NEED_PASSWORD: 1, + INCORRECT_PASSWORD: 2 +}; + +var PasswordException = (function PasswordExceptionClosure() { + function PasswordException(msg, code) { + this.name = 'PasswordException'; + this.message = msg; + this.code = code; + } + + PasswordException.prototype = new Error(); + PasswordException.constructor = PasswordException; + + return PasswordException; +})(); +PDFJS.PasswordException = PasswordException; + +var UnknownErrorException = (function UnknownErrorExceptionClosure() { + function UnknownErrorException(msg, details) { + this.name = 'UnknownErrorException'; + this.message = msg; + this.details = details; + } + + UnknownErrorException.prototype = new Error(); + UnknownErrorException.constructor = UnknownErrorException; + + return UnknownErrorException; +})(); +PDFJS.UnknownErrorException = UnknownErrorException; + +var InvalidPDFException = (function InvalidPDFExceptionClosure() { + function InvalidPDFException(msg) { + this.name = 'InvalidPDFException'; + this.message = msg; + } + + InvalidPDFException.prototype = new Error(); + InvalidPDFException.constructor = InvalidPDFException; + + return InvalidPDFException; +})(); +PDFJS.InvalidPDFException = InvalidPDFException; + +var MissingPDFException = (function MissingPDFExceptionClosure() { + function MissingPDFException(msg) { + this.name = 'MissingPDFException'; + this.message = msg; + } + + MissingPDFException.prototype = new Error(); + MissingPDFException.constructor = MissingPDFException; + + return MissingPDFException; +})(); +PDFJS.MissingPDFException = MissingPDFException; + +var UnexpectedResponseException = + (function UnexpectedResponseExceptionClosure() { + function UnexpectedResponseException(msg, status) { + this.name = 'UnexpectedResponseException'; + this.message = msg; + this.status = status; + } + + UnexpectedResponseException.prototype = new Error(); + UnexpectedResponseException.constructor = UnexpectedResponseException; + + return UnexpectedResponseException; +})(); +PDFJS.UnexpectedResponseException = UnexpectedResponseException; + +var NotImplementedException = (function NotImplementedExceptionClosure() { + function NotImplementedException(msg) { + this.message = msg; + } + + NotImplementedException.prototype = new Error(); + NotImplementedException.prototype.name = 'NotImplementedException'; + NotImplementedException.constructor = NotImplementedException; + + return NotImplementedException; +})(); + +var MissingDataException = (function MissingDataExceptionClosure() { + function MissingDataException(begin, end) { + this.begin = begin; + this.end = end; + this.message = 'Missing data [' + begin + ', ' + end + ')'; + } + + MissingDataException.prototype = new Error(); + MissingDataException.prototype.name = 'MissingDataException'; + MissingDataException.constructor = MissingDataException; + + return MissingDataException; +})(); + +var XRefParseException = (function XRefParseExceptionClosure() { + function XRefParseException(msg) { + this.message = msg; + } + + XRefParseException.prototype = new Error(); + XRefParseException.prototype.name = 'XRefParseException'; + XRefParseException.constructor = XRefParseException; + + return XRefParseException; +})(); + + +function bytesToString(bytes) { + assert(bytes !== null && typeof bytes === 'object' && + bytes.length !== undefined, 'Invalid argument for bytesToString'); + var length = bytes.length; + var MAX_ARGUMENT_COUNT = 8192; + if (length < MAX_ARGUMENT_COUNT) { + return String.fromCharCode.apply(null, bytes); + } + var strBuf = []; + for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) { + var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length); + var chunk = bytes.subarray(i, chunkEnd); + strBuf.push(String.fromCharCode.apply(null, chunk)); + } + return strBuf.join(''); +} + +function stringToBytes(str) { + assert(typeof str === 'string', 'Invalid argument for stringToBytes'); + var length = str.length; + var bytes = new Uint8Array(length); + for (var i = 0; i < length; ++i) { + bytes[i] = str.charCodeAt(i) & 0xFF; + } + return bytes; +} + +function string32(value) { + return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff, + (value >> 8) & 0xff, value & 0xff); +} + +function log2(x) { + var n = 1, i = 0; + while (x > n) { + n <<= 1; + i++; + } + return i; +} + +function readInt8(data, start) { + return (data[start] << 24) >> 24; +} + +function readUint16(data, offset) { + return (data[offset] << 8) | data[offset + 1]; +} + +function readUint32(data, offset) { + return ((data[offset] << 24) | (data[offset + 1] << 16) | + (data[offset + 2] << 8) | data[offset + 3]) >>> 0; +} + +// Lazy test the endianness of the platform +// NOTE: This will be 'true' for simulated TypedArrays +function isLittleEndian() { + var buffer8 = new Uint8Array(2); + buffer8[0] = 1; + var buffer16 = new Uint16Array(buffer8.buffer); + return (buffer16[0] === 1); +} + +Object.defineProperty(PDFJS, 'isLittleEndian', { + configurable: true, + get: function PDFJS_isLittleEndian() { + return shadow(PDFJS, 'isLittleEndian', isLittleEndian()); + } +}); + + PDFJS.hasCanvasTypedArrays = true; + +var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0]; + +var Util = PDFJS.Util = (function UtilClosure() { + function Util() {} + + var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')']; + + // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids + // creating many intermediate strings. + Util.makeCssRgb = function Util_makeCssRgb(r, g, b) { + rgbBuf[1] = r; + rgbBuf[3] = g; + rgbBuf[5] = b; + return rgbBuf.join(''); + }; + + // Concatenates two transformation matrices together and returns the result. + Util.transform = function Util_transform(m1, m2) { + return [ + m1[0] * m2[0] + m1[2] * m2[1], + m1[1] * m2[0] + m1[3] * m2[1], + m1[0] * m2[2] + m1[2] * m2[3], + m1[1] * m2[2] + m1[3] * m2[3], + m1[0] * m2[4] + m1[2] * m2[5] + m1[4], + m1[1] * m2[4] + m1[3] * m2[5] + m1[5] + ]; + }; + + // For 2d affine transforms + Util.applyTransform = function Util_applyTransform(p, m) { + var xt = p[0] * m[0] + p[1] * m[2] + m[4]; + var yt = p[0] * m[1] + p[1] * m[3] + m[5]; + return [xt, yt]; + }; + + Util.applyInverseTransform = function Util_applyInverseTransform(p, m) { + var d = m[0] * m[3] - m[1] * m[2]; + var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d; + var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d; + return [xt, yt]; + }; + + // Applies the transform to the rectangle and finds the minimum axially + // aligned bounding box. + Util.getAxialAlignedBoundingBox = + function Util_getAxialAlignedBoundingBox(r, m) { + + var p1 = Util.applyTransform(r, m); + var p2 = Util.applyTransform(r.slice(2, 4), m); + var p3 = Util.applyTransform([r[0], r[3]], m); + var p4 = Util.applyTransform([r[2], r[1]], m); + return [ + Math.min(p1[0], p2[0], p3[0], p4[0]), + Math.min(p1[1], p2[1], p3[1], p4[1]), + Math.max(p1[0], p2[0], p3[0], p4[0]), + Math.max(p1[1], p2[1], p3[1], p4[1]) + ]; + }; + + Util.inverseTransform = function Util_inverseTransform(m) { + var d = m[0] * m[3] - m[1] * m[2]; + return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d, + (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d]; + }; + + // Apply a generic 3d matrix M on a 3-vector v: + // | a b c | | X | + // | d e f | x | Y | + // | g h i | | Z | + // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i], + // with v as [X,Y,Z] + Util.apply3dTransform = function Util_apply3dTransform(m, v) { + return [ + m[0] * v[0] + m[1] * v[1] + m[2] * v[2], + m[3] * v[0] + m[4] * v[1] + m[5] * v[2], + m[6] * v[0] + m[7] * v[1] + m[8] * v[2] + ]; + }; + + // This calculation uses Singular Value Decomposition. + // The SVD can be represented with formula A = USV. We are interested in the + // matrix S here because it represents the scale values. + Util.singularValueDecompose2dScale = + function Util_singularValueDecompose2dScale(m) { + + var transpose = [m[0], m[2], m[1], m[3]]; + + // Multiply matrix m with its transpose. + var a = m[0] * transpose[0] + m[1] * transpose[2]; + var b = m[0] * transpose[1] + m[1] * transpose[3]; + var c = m[2] * transpose[0] + m[3] * transpose[2]; + var d = m[2] * transpose[1] + m[3] * transpose[3]; + + // Solve the second degree polynomial to get roots. + var first = (a + d) / 2; + var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2; + var sx = first + second || 1; + var sy = first - second || 1; + + // Scale values are the square roots of the eigenvalues. + return [Math.sqrt(sx), Math.sqrt(sy)]; + }; + + // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2) + // For coordinate systems whose origin lies in the bottom-left, this + // means normalization to (BL,TR) ordering. For systems with origin in the + // top-left, this means (TL,BR) ordering. + Util.normalizeRect = function Util_normalizeRect(rect) { + var r = rect.slice(0); // clone rect + if (rect[0] > rect[2]) { + r[0] = rect[2]; + r[2] = rect[0]; + } + if (rect[1] > rect[3]) { + r[1] = rect[3]; + r[3] = rect[1]; + } + return r; + }; + + // Returns a rectangle [x1, y1, x2, y2] corresponding to the + // intersection of rect1 and rect2. If no intersection, returns 'false' + // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2] + Util.intersect = function Util_intersect(rect1, rect2) { + function compare(a, b) { + return a - b; + } + + // Order points along the axes + var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare), + orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare), + result = []; + + rect1 = Util.normalizeRect(rect1); + rect2 = Util.normalizeRect(rect2); + + // X: first and second points belong to different rectangles? + if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) || + (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) { + // Intersection must be between second and third points + result[0] = orderedX[1]; + result[2] = orderedX[2]; + } else { + return false; + } + + // Y: first and second points belong to different rectangles? + if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) || + (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) { + // Intersection must be between second and third points + result[1] = orderedY[1]; + result[3] = orderedY[2]; + } else { + return false; + } + + return result; + }; + + Util.sign = function Util_sign(num) { + return num < 0 ? -1 : 1; + }; + + Util.appendToArray = function Util_appendToArray(arr1, arr2) { + Array.prototype.push.apply(arr1, arr2); + }; + + Util.prependToArray = function Util_prependToArray(arr1, arr2) { + Array.prototype.unshift.apply(arr1, arr2); + }; + + Util.extendObj = function extendObj(obj1, obj2) { + for (var key in obj2) { + obj1[key] = obj2[key]; + } + }; + + Util.getInheritableProperty = function Util_getInheritableProperty(dict, + name) { + while (dict && !dict.has(name)) { + dict = dict.get('Parent'); + } + if (!dict) { + return null; + } + return dict.get(name); + }; + + Util.inherit = function Util_inherit(sub, base, prototype) { + sub.prototype = Object.create(base.prototype); + sub.prototype.constructor = sub; + for (var prop in prototype) { + sub.prototype[prop] = prototype[prop]; + } + }; + + Util.loadScript = function Util_loadScript(src, callback) { + var script = document.createElement('script'); + var loaded = false; + script.setAttribute('src', src); + if (callback) { + script.onload = function() { + if (!loaded) { + callback(); + } + loaded = true; + }; + } + document.getElementsByTagName('head')[0].appendChild(script); + }; + + return Util; +})(); + +/** + * PDF page viewport created based on scale, rotation and offset. + * @class + * @alias PDFJS.PageViewport + */ +var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() { + /** + * @constructor + * @private + * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates. + * @param scale {number} scale of the viewport. + * @param rotation {number} rotations of the viewport in degrees. + * @param offsetX {number} offset X + * @param offsetY {number} offset Y + * @param dontFlip {boolean} if true, axis Y will not be flipped. + */ + function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) { + this.viewBox = viewBox; + this.scale = scale; + this.rotation = rotation; + this.offsetX = offsetX; + this.offsetY = offsetY; + + // creating transform to convert pdf coordinate system to the normal + // canvas like coordinates taking in account scale and rotation + var centerX = (viewBox[2] + viewBox[0]) / 2; + var centerY = (viewBox[3] + viewBox[1]) / 2; + var rotateA, rotateB, rotateC, rotateD; + rotation = rotation % 360; + rotation = rotation < 0 ? rotation + 360 : rotation; + switch (rotation) { + case 180: + rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1; + break; + case 90: + rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0; + break; + case 270: + rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0; + break; + //case 0: + default: + rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1; + break; + } + + if (dontFlip) { + rotateC = -rotateC; rotateD = -rotateD; + } + + var offsetCanvasX, offsetCanvasY; + var width, height; + if (rotateA === 0) { + offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX; + offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY; + width = Math.abs(viewBox[3] - viewBox[1]) * scale; + height = Math.abs(viewBox[2] - viewBox[0]) * scale; + } else { + offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX; + offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY; + width = Math.abs(viewBox[2] - viewBox[0]) * scale; + height = Math.abs(viewBox[3] - viewBox[1]) * scale; + } + // creating transform for the following operations: + // translate(-centerX, -centerY), rotate and flip vertically, + // scale, and translate(offsetCanvasX, offsetCanvasY) + this.transform = [ + rotateA * scale, + rotateB * scale, + rotateC * scale, + rotateD * scale, + offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, + offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY + ]; + + this.width = width; + this.height = height; + this.fontScale = scale; + } + PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ { + /** + * Clones viewport with additional properties. + * @param args {Object} (optional) If specified, may contain the 'scale' or + * 'rotation' properties to override the corresponding properties in + * the cloned viewport. + * @returns {PDFJS.PageViewport} Cloned viewport. + */ + clone: function PageViewPort_clone(args) { + args = args || {}; + var scale = 'scale' in args ? args.scale : this.scale; + var rotation = 'rotation' in args ? args.rotation : this.rotation; + return new PageViewport(this.viewBox.slice(), scale, rotation, + this.offsetX, this.offsetY, args.dontFlip); + }, + /** + * Converts PDF point to the viewport coordinates. For examples, useful for + * converting PDF location into canvas pixel coordinates. + * @param x {number} X coordinate. + * @param y {number} Y coordinate. + * @returns {Object} Object that contains 'x' and 'y' properties of the + * point in the viewport coordinate space. + * @see {@link convertToPdfPoint} + * @see {@link convertToViewportRectangle} + */ + convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) { + return Util.applyTransform([x, y], this.transform); + }, + /** + * Converts PDF rectangle to the viewport coordinates. + * @param rect {Array} xMin, yMin, xMax and yMax coordinates. + * @returns {Array} Contains corresponding coordinates of the rectangle + * in the viewport coordinate space. + * @see {@link convertToViewportPoint} + */ + convertToViewportRectangle: + function PageViewport_convertToViewportRectangle(rect) { + var tl = Util.applyTransform([rect[0], rect[1]], this.transform); + var br = Util.applyTransform([rect[2], rect[3]], this.transform); + return [tl[0], tl[1], br[0], br[1]]; + }, + /** + * Converts viewport coordinates to the PDF location. For examples, useful + * for converting canvas pixel location into PDF one. + * @param x {number} X coordinate. + * @param y {number} Y coordinate. + * @returns {Object} Object that contains 'x' and 'y' properties of the + * point in the PDF coordinate space. + * @see {@link convertToViewportPoint} + */ + convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) { + return Util.applyInverseTransform([x, y], this.transform); + } + }; + return PageViewport; +})(); + +var PDFStringTranslateTable = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, + 0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, + 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160, + 0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC +]; + +function stringToPDFString(str) { + var i, n = str.length, strBuf = []; + if (str[0] === '\xFE' && str[1] === '\xFF') { + // UTF16BE BOM + for (i = 2; i < n; i += 2) { + strBuf.push(String.fromCharCode( + (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1))); + } + } else { + for (i = 0; i < n; ++i) { + var code = PDFStringTranslateTable[str.charCodeAt(i)]; + strBuf.push(code ? String.fromCharCode(code) : str.charAt(i)); + } + } + return strBuf.join(''); +} + +function stringToUTF8String(str) { + return decodeURIComponent(escape(str)); +} + +function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); +} + +function isEmptyObj(obj) { + for (var key in obj) { + return false; + } + return true; +} + +function isBool(v) { + return typeof v === 'boolean'; +} + +function isInt(v) { + return typeof v === 'number' && ((v | 0) === v); +} + +function isNum(v) { + return typeof v === 'number'; +} + +function isString(v) { + return typeof v === 'string'; +} + +function isArray(v) { + return v instanceof Array; +} + +function isArrayBuffer(v) { + return typeof v === 'object' && v !== null && v.byteLength !== undefined; +} + +/** + * Promise Capability object. + * + * @typedef {Object} PromiseCapability + * @property {Promise} promise - A promise object. + * @property {function} resolve - Fullfills the promise. + * @property {function} reject - Rejects the promise. + */ + +/** + * Creates a promise capability object. + * @alias PDFJS.createPromiseCapability + * + * @return {PromiseCapability} A capability object contains: + * - a Promise, resolve and reject methods. + */ +function createPromiseCapability() { + var capability = {}; + capability.promise = new Promise(function (resolve, reject) { + capability.resolve = resolve; + capability.reject = reject; + }); + return capability; +} + +PDFJS.createPromiseCapability = createPromiseCapability; + +/** + * Polyfill for Promises: + * The following promise implementation tries to generally implement the + * Promise/A+ spec. Some notable differences from other promise libaries are: + * - There currently isn't a seperate deferred and promise object. + * - Unhandled rejections eventually show an error if they aren't handled. + * + * Based off of the work in: + * https://bugzilla.mozilla.org/show_bug.cgi?id=810490 + */ +(function PromiseClosure() { + if (globalScope.Promise) { + // Promises existing in the DOM/Worker, checking presence of all/resolve + if (typeof globalScope.Promise.all !== 'function') { + globalScope.Promise.all = function (iterable) { + var count = 0, results = [], resolve, reject; + var promise = new globalScope.Promise(function (resolve_, reject_) { + resolve = resolve_; + reject = reject_; + }); + iterable.forEach(function (p, i) { + count++; + p.then(function (result) { + results[i] = result; + count--; + if (count === 0) { + resolve(results); + } + }, reject); + }); + if (count === 0) { + resolve(results); + } + return promise; + }; + } + if (typeof globalScope.Promise.resolve !== 'function') { + globalScope.Promise.resolve = function (value) { + return new globalScope.Promise(function (resolve) { resolve(value); }); + }; + } + if (typeof globalScope.Promise.reject !== 'function') { + globalScope.Promise.reject = function (reason) { + return new globalScope.Promise(function (resolve, reject) { + reject(reason); + }); + }; + } + if (typeof globalScope.Promise.prototype.catch !== 'function') { + globalScope.Promise.prototype.catch = function (onReject) { + return globalScope.Promise.prototype.then(undefined, onReject); + }; + } + return; + } + throw new Error('DOM Promise is not present'); +})(); + +var StatTimer = (function StatTimerClosure() { + function rpad(str, pad, length) { + while (str.length < length) { + str += pad; + } + return str; + } + function StatTimer() { + this.started = {}; + this.times = []; + this.enabled = true; + } + StatTimer.prototype = { + time: function StatTimer_time(name) { + if (!this.enabled) { + return; + } + if (name in this.started) { + warn('Timer is already running for ' + name); + } + this.started[name] = Date.now(); + }, + timeEnd: function StatTimer_timeEnd(name) { + if (!this.enabled) { + return; + } + if (!(name in this.started)) { + warn('Timer has not been started for ' + name); + } + this.times.push({ + 'name': name, + 'start': this.started[name], + 'end': Date.now() + }); + // Remove timer from started so it can be called again. + delete this.started[name]; + }, + toString: function StatTimer_toString() { + var i, ii; + var times = this.times; + var out = ''; + // Find the longest name for padding purposes. + var longest = 0; + for (i = 0, ii = times.length; i < ii; ++i) { + var name = times[i]['name']; + if (name.length > longest) { + longest = name.length; + } + } + for (i = 0, ii = times.length; i < ii; ++i) { + var span = times[i]; + var duration = span.end - span.start; + out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n'; + } + return out; + } + }; + return StatTimer; +})(); + +PDFJS.createBlob = function createBlob(data, contentType) { + if (typeof Blob !== 'undefined') { + return new Blob([data], { type: contentType }); + } + // Blob builder is deprecated in FF14 and removed in FF18. + var bb = new MozBlobBuilder(); + bb.append(data); + return bb.getBlob(contentType); +}; + +PDFJS.createObjectURL = (function createObjectURLClosure() { + // Blob/createObjectURL is not available, falling back to data schema. + var digits = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + + return function createObjectURL(data, contentType) { + if (!PDFJS.disableCreateObjectURL && + typeof URL !== 'undefined' && URL.createObjectURL) { + var blob = PDFJS.createBlob(data, contentType); + return URL.createObjectURL(blob); + } + + var buffer = 'data:' + contentType + ';base64,'; + for (var i = 0, ii = data.length; i < ii; i += 3) { + var b1 = data[i] & 0xFF; + var b2 = data[i + 1] & 0xFF; + var b3 = data[i + 2] & 0xFF; + var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4); + var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64; + var d4 = i + 2 < ii ? (b3 & 0x3F) : 64; + buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4]; + } + return buffer; + }; +})(); + +function MessageHandler(sourceName, targetName, comObj) { + this.sourceName = sourceName; + this.targetName = targetName; + this.comObj = comObj; + this.callbackIndex = 1; + this.postMessageTransfers = true; + var callbacksCapabilities = this.callbacksCapabilities = {}; + var ah = this.actionHandler = {}; + + this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) { + var data = event.data; + if (data.targetName !== this.sourceName) { + return; + } + if (data.isReply) { + var callbackId = data.callbackId; + if (data.callbackId in callbacksCapabilities) { + var callback = callbacksCapabilities[callbackId]; + delete callbacksCapabilities[callbackId]; + if ('error' in data) { + callback.reject(data.error); + } else { + callback.resolve(data.data); + } + } else { + error('Cannot resolve callback ' + callbackId); + } + } else if (data.action in ah) { + var action = ah[data.action]; + if (data.callbackId) { + var sourceName = this.sourceName; + var targetName = data.sourceName; + Promise.resolve().then(function () { + return action[0].call(action[1], data.data); + }).then(function (result) { + comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, + isReply: true, + callbackId: data.callbackId, + data: result + }); + }, function (reason) { + if (reason instanceof Error) { + // Serialize error to avoid "DataCloneError" + reason = reason + ''; + } + comObj.postMessage({ + sourceName: sourceName, + targetName: targetName, + isReply: true, + callbackId: data.callbackId, + error: reason + }); + }); + } else { + action[0].call(action[1], data.data); + } + } else { + error('Unknown action from worker: ' + data.action); + } + }.bind(this); + comObj.addEventListener('message', this._onComObjOnMessage); +} + +MessageHandler.prototype = { + on: function messageHandlerOn(actionName, handler, scope) { + var ah = this.actionHandler; + if (ah[actionName]) { + error('There is already an actionName called "' + actionName + '"'); + } + ah[actionName] = [handler, scope]; + }, + /** + * Sends a message to the comObj to invoke the action with the supplied data. + * @param {String} actionName Action to call. + * @param {JSON} data JSON data to send. + * @param {Array} [transfers] Optional list of transfers/ArrayBuffers + */ + send: function messageHandlerSend(actionName, data, transfers) { + var message = { + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data: data + }; + this.postMessage(message, transfers); + }, + /** + * Sends a message to the comObj to invoke the action with the supplied data. + * Expects that other side will callback with the response. + * @param {String} actionName Action to call. + * @param {JSON} data JSON data to send. + * @param {Array} [transfers] Optional list of transfers/ArrayBuffers. + * @returns {Promise} Promise to be resolved with response data. + */ + sendWithPromise: + function messageHandlerSendWithPromise(actionName, data, transfers) { + var callbackId = this.callbackIndex++; + var message = { + sourceName: this.sourceName, + targetName: this.targetName, + action: actionName, + data: data, + callbackId: callbackId + }; + var capability = createPromiseCapability(); + this.callbacksCapabilities[callbackId] = capability; + try { + this.postMessage(message, transfers); + } catch (e) { + capability.reject(e); + } + return capability.promise; + }, + /** + * Sends raw message to the comObj. + * @private + * @param message {Object} Raw message. + * @param transfers List of transfers/ArrayBuffers, or undefined. + */ + postMessage: function (message, transfers) { + if (transfers && this.postMessageTransfers) { + this.comObj.postMessage(message, transfers); + } else { + this.comObj.postMessage(message); + } + }, + + destroy: function () { + this.comObj.removeEventListener('message', this._onComObjOnMessage); + } +}; + +function loadJpegStream(id, imageUrl, objs) { + var img = new Image(); + img.onload = (function loadJpegStream_onloadClosure() { + objs.resolve(id, img); + }); + img.onerror = (function loadJpegStream_onerrorClosure() { + objs.resolve(id, null); + warn('Error during JPEG image loading'); + }); + img.src = imageUrl; +} + +exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX; +exports.IDENTITY_MATRIX = IDENTITY_MATRIX; +exports.OPS = OPS; +exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES; +exports.AnnotationBorderStyleType = AnnotationBorderStyleType; +exports.AnnotationFlag = AnnotationFlag; +exports.AnnotationType = AnnotationType; +exports.FontType = FontType; +exports.ImageKind = ImageKind; +exports.InvalidPDFException = InvalidPDFException; +exports.LinkTarget = LinkTarget; +exports.LinkTargetStringMap = LinkTargetStringMap; +exports.MessageHandler = MessageHandler; +exports.MissingDataException = MissingDataException; +exports.MissingPDFException = MissingPDFException; +exports.NotImplementedException = NotImplementedException; +exports.PasswordException = PasswordException; +exports.PasswordResponses = PasswordResponses; +exports.StatTimer = StatTimer; +exports.StreamType = StreamType; +exports.TextRenderingMode = TextRenderingMode; +exports.UnexpectedResponseException = UnexpectedResponseException; +exports.UnknownErrorException = UnknownErrorException; +exports.Util = Util; +exports.XRefParseException = XRefParseException; +exports.assert = assert; +exports.bytesToString = bytesToString; +exports.combineUrl = combineUrl; +exports.createPromiseCapability = createPromiseCapability; +exports.deprecated = deprecated; +exports.error = error; +exports.info = info; +exports.isArray = isArray; +exports.isArrayBuffer = isArrayBuffer; +exports.isBool = isBool; +exports.isEmptyObj = isEmptyObj; +exports.isExternalLinkTargetSet = isExternalLinkTargetSet; +exports.isInt = isInt; +exports.isNum = isNum; +exports.isString = isString; +exports.isValidUrl = isValidUrl; +exports.loadJpegStream = loadJpegStream; +exports.log2 = log2; +exports.readInt8 = readInt8; +exports.readUint16 = readUint16; +exports.readUint32 = readUint32; +exports.shadow = shadow; +exports.string32 = string32; +exports.stringToBytes = stringToBytes; +exports.stringToPDFString = stringToPDFString; +exports.stringToUTF8String = stringToUTF8String; +exports.utf8StringToString = utf8StringToString; +exports.warn = warn; +})); + + +(function (root, factory) { + { factory((root.pdfjsCoreChunkedStream = {}), root.pdfjsSharedUtil); } }(this, function (exports, sharedUtil) { var MissingDataException = sharedUtil.MissingDataException; var assert = sharedUtil.assert; var createPromiseCapability = sharedUtil.createPromiseCapability; var isInt = sharedUtil.isInt; @@ -17380,16 +17381,17 @@ var PasswordResponses = sharedUtil.Passw var bytesToString = sharedUtil.bytesToString; var error = sharedUtil.error; var isInt = sharedUtil.isInt; var stringToBytes = sharedUtil.stringToBytes; var utf8StringToString = sharedUtil.utf8StringToString; var warn = sharedUtil.warn; var Name = corePrimitives.Name; var isName = corePrimitives.isName; +var isDict = corePrimitives.isDict; var DecryptStream = coreStream.DecryptStream; var ARCFourCipher = (function ARCFourCipherClosure() { function ARCFourCipher(key) { this.a = 0; this.b = 0; var s = new Uint8Array(256); var i, j = 0, tmp, keyLength = key.length; @@ -19263,17 +19265,37 @@ var CipherTransformFactory = (function C this.dict = dict; var algorithm = dict.get('V'); if (!isInt(algorithm) || (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5)) { error('unsupported encryption algorithm'); } this.algorithm = algorithm; - var keyLength = dict.get('Length') || 40; + var keyLength = dict.get('Length'); + if (!keyLength) { + // Spec asks to rely on encryption dictionary's Length entry, however + // some PDFs don't have it. Trying to recover. + if (algorithm <= 3) { + // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value. + keyLength = 40; + } else { + // Trying to find default handler -- it usually has Length. + var cfDict = dict.get('CF'); + var streamCryptoName = dict.get('StmF'); + if (isDict(cfDict) && isName(streamCryptoName)) { + var handlerDict = cfDict.get(streamCryptoName.name); + keyLength = (handlerDict && handlerDict.get('Length')) || 128; + if (keyLength < 40) { + // Sometimes it's incorrect value of bits, generators specify bytes. + keyLength <<= 3; + } + } + } + } if (!isInt(keyLength) || keyLength < 40 || (keyLength % 8) !== 0) { error('invalid key length'); } // prepare keys var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32); var userPassword = stringToBytes(dict.get('U')).subarray(0, 32); @@ -38224,18 +38246,16 @@ var warn = sharedUtil.warn; var Dict = corePrimitives.Dict; var isDict = corePrimitives.isDict; var isName = corePrimitives.isName; var Stream = coreStream.Stream; var ColorSpace = coreColorSpace.ColorSpace; var ObjectLoader = coreObj.ObjectLoader; var OperatorList = coreEvaluator.OperatorList; -var DEFAULT_ICON_SIZE = 22; // px - /** * @class * @alias AnnotationFactory */ function AnnotationFactory() {} AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ { /** * @param {XRef} xref @@ -38267,16 +38287,22 @@ AnnotationFactory.prototype = /** @lends case 'Widget': var fieldType = Util.getInheritableProperty(dict, 'FT'); if (isName(fieldType) && fieldType.name === 'Tx') { return new TextWidgetAnnotation(parameters); } return new WidgetAnnotation(parameters); + case 'Popup': + return new PopupAnnotation(parameters); + + case 'Underline': + return new UnderlineAnnotation(parameters); + default: warn('Unimplemented annotation type "' + subtype + '", ' + 'falling back to base annotation'); return new Annotation(parameters); } } }; @@ -38332,17 +38358,17 @@ var Annotation = (function AnnotationClo this.setFlags(dict.get('F')); this.setRectangle(dict.get('Rect')); this.setColor(dict.get('C')); this.setBorderStyle(dict); this.appearance = getDefaultAppearance(dict); // Expose public properties using a data object. this.data = {}; - this.data.id = params.ref.num; + this.data.id = params.ref.toString(); this.data.subtype = dict.get('Subtype').name; this.data.annotationFlags = this.flags; this.data.rect = this.rectangle; this.data.color = this.color; this.data.borderStyle = this.borderStyle; this.data.hasAppearance = !!this.appearance; } @@ -38811,39 +38837,45 @@ var TextWidgetAnnotation = (function Tex }); } }); return TextWidgetAnnotation; })(); var TextAnnotation = (function TextAnnotationClosure() { - function TextAnnotation(params) { - Annotation.call(this, params); - - var dict = params.dict; - var data = this.data; - - var content = dict.get('Contents'); - var title = dict.get('T'); - data.annotationType = AnnotationType.TEXT; - data.content = stringToPDFString(content || ''); - data.title = stringToPDFString(title || ''); - data.hasHtml = true; - - if (data.hasAppearance) { - data.name = 'NoIcon'; - } else { - data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE; - data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE; - data.name = dict.has('Name') ? dict.get('Name').name : 'Note'; - } - - if (dict.has('C')) { - data.hasBgColor = true; + var DEFAULT_ICON_SIZE = 22; // px + + function TextAnnotation(parameters) { + Annotation.call(this, parameters); + + this.data.annotationType = AnnotationType.TEXT; + this.data.hasHtml = true; + + var dict = parameters.dict; + if (this.data.hasAppearance) { + this.data.name = 'NoIcon'; + } else { + this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE; + this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE; + this.data.name = dict.has('Name') ? dict.get('Name').name : 'Note'; + } + + if (!dict.has('C')) { + // Fall back to the default background color. + this.data.color = null; + } + + this.data.hasPopup = dict.has('Popup'); + if (!this.data.hasPopup) { + // There is no associated Popup annotation, so the Text annotation + // must create its own popup. + this.data.title = stringToPDFString(dict.get('T') || ''); + this.data.contents = stringToPDFString(dict.get('Contents') || ''); + this.data.hasHtml = (this.data.title || this.data.contents); } } Util.inherit(TextAnnotation, Annotation, {}); return TextAnnotation; })(); @@ -38918,16 +38950,65 @@ var LinkAnnotation = (function LinkAnnot return url; } Util.inherit(LinkAnnotation, Annotation, {}); return LinkAnnotation; })(); +var PopupAnnotation = (function PopupAnnotationClosure() { + function PopupAnnotation(parameters) { + Annotation.call(this, parameters); + + this.data.annotationType = AnnotationType.POPUP; + + var dict = parameters.dict; + var parentItem = dict.get('Parent'); + if (!parentItem) { + warn('Popup annotation has a missing or invalid parent annotation.'); + return; + } + + this.data.parentId = dict.getRaw('Parent').toString(); + this.data.title = stringToPDFString(parentItem.get('T') || ''); + this.data.contents = stringToPDFString(parentItem.get('Contents') || ''); + + if (!parentItem.has('C')) { + // Fall back to the default background color. + this.data.color = null; + } else { + this.setColor(parentItem.get('C')); + this.data.color = this.color; + } + + this.data.hasHtml = (this.data.title || this.data.contents); + } + + Util.inherit(PopupAnnotation, Annotation, {}); + + return PopupAnnotation; +})(); + +var UnderlineAnnotation = (function UnderlineAnnotationClosure() { + function UnderlineAnnotation(parameters) { + Annotation.call(this, parameters); + + this.data.annotationType = AnnotationType.UNDERLINE; + this.data.hasHtml = true; + + // PDF viewers completely ignore any border styles. + this.data.borderStyle.setWidth(0); + } + + Util.inherit(UnderlineAnnotation, Annotation, {}); + + return UnderlineAnnotation; +})(); + exports.Annotation = Annotation; exports.AnnotationBorderStyle = AnnotationBorderStyle; exports.AnnotationFactory = AnnotationFactory; })); (function (root, factory) { { @@ -39781,17 +39862,23 @@ var WorkerTask = (function WorkerTaskClo } }; return WorkerTask; })(); var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { setup: function wphSetup(handler, port) { + var testMessageProcessed = false; handler.on('test', function wphSetupTest(data) { + if (testMessageProcessed) { + return; // we already processed 'test' message once + } + testMessageProcessed = true; + // check if Uint8Array can be sent to worker if (!(data instanceof Uint8Array)) { handler.send('test', 'main', false); return; } // making sure postMessage transfers are working var supportTransfers = data[0] === 255; handler.postMessageTransfers = supportTransfers; @@ -40308,60 +40395,27 @@ var WorkerMessageHandler = PDFJS.WorkerM handler.on('Ready', function wphReady(data) { setupDoc(docParams); docParams = null; // we don't need docParams anymore -- saving memory. }); return workerHandlerName; } }; -var consoleTimer = {}; - -var workerConsole = { - log: function log() { - var args = Array.prototype.slice.call(arguments); - globalScope.postMessage({ - targetName: 'main', - action: 'console_log', - data: args - }); - }, - - error: function error() { - var args = Array.prototype.slice.call(arguments); - globalScope.postMessage({ - targetName: 'main', - action: 'console_error', - data: args - }); - throw 'pdf.js execution error'; - }, - - time: function time(name) { - consoleTimer[name] = Date.now(); - }, - - timeEnd: function timeEnd(name) { - var time = consoleTimer[name]; - if (!time) { - error('Unknown timer name ' + name); - } - this.log('Timer:', name, Date.now() - time); - } -}; - - -// Worker thread? -if (typeof window === 'undefined' && typeof require === 'undefined') { - if (!('console' in globalScope)) { - globalScope.console = workerConsole; - } +function initializeWorker() { var handler = new MessageHandler('worker', 'main', self); WorkerMessageHandler.setup(handler, self); + handler.send('ready', null); +} + +// Worker thread (and not node.js)? +if (typeof window === 'undefined' && + !(typeof module !== 'undefined' && module.require)) { + initializeWorker(); } exports.WorkerTask = WorkerTask; exports.WorkerMessageHandler = WorkerMessageHandler; })); }).call((typeof window === 'undefined') ? this : window);
--- a/browser/extensions/pdfjs/content/network.js +++ b/browser/extensions/pdfjs/content/network.js @@ -259,8 +259,9 @@ var NetworkManager = (function NetworkMa delete this.pendingRequests[xhrId]; xhr.abort(); } }; return NetworkManager; })(); +
--- a/browser/extensions/pdfjs/content/web/viewer.css +++ b/browser/extensions/pdfjs/content/web/viewer.css @@ -76,62 +76,68 @@ top: 0px; } .annotationLayer section { position: absolute; } -.annotationLayer .annotLink > a:hover { - opacity: 0.2; - background: #ff0; - box-shadow: 0px 2px 10px #ff0; -} - -.annotationLayer .annotText > img { - position: absolute; - cursor: pointer; -} - -.annotationLayer .annotTextContentWrapper { - position: absolute; - width: 20em; -} - -.annotationLayer .annotTextContent { - z-index: 200; - float: left; - max-width: 20em; - background-color: #FFFF99; - box-shadow: 0px 2px 5px #333; - border-radius: 2px; - padding: 0.6em; - cursor: pointer; -} - -.annotationLayer .annotTextContent > h1 { - font-size: 1em; - border-bottom: 1px solid #000000; - padding-bottom: 0.2em; -} - -.annotationLayer .annotTextContent > p { - padding-top: 0.2em; -} - -.annotationLayer .annotLink > a { +.annotationLayer .linkAnnotation > a { position: absolute; font-size: 1em; top: 0; left: 0; width: 100%; height: 100%; } +.annotationLayer .linkAnnotation > a:hover { + opacity: 0.2; + background: #ff0; + box-shadow: 0px 2px 10px #ff0; +} + +.annotationLayer .textAnnotation img { + position: absolute; + cursor: pointer; +} + +.annotationLayer .popupWrapper { + position: absolute; + width: 20em; +} + +.annotationLayer .popup { + position: absolute; + z-index: 200; + max-width: 20em; + background-color: #FFFF99; + box-shadow: 0px 2px 5px #333; + border-radius: 2px; + padding: 0.6em; + margin-left: 5px; + cursor: pointer; + word-wrap: break-word; +} + +.annotationLayer .popup h1 { + font-size: 1em; + border-bottom: 1px solid #000000; + padding-bottom: 0.2em; +} + +.annotationLayer .popup p { + padding-top: 0.2em; +} + +.annotationLayer .underlineAnnotation { + cursor: pointer; +} + .pdfViewer .canvasWrapper { overflow: hidden; } .pdfViewer .page { direction: ltr; width: 816px; height: 1056px;
--- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -29,20 +29,22 @@ var DEFAULT_URL = 'compressed.tracemonke var DEFAULT_SCALE_DELTA = 1.1; var MIN_SCALE = 0.25; var MAX_SCALE = 10.0; var SCALE_SELECT_CONTAINER_PADDING = 8; var SCALE_SELECT_PADDING = 22; var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading'; var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; -PDFJS.imageResourcesPath = './images/'; +function configure(PDFJS) { + PDFJS.imageResourcesPath = './images/'; PDFJS.workerSrc = '../build/pdf.worker.js'; PDFJS.cMapUrl = '../web/cmaps/'; PDFJS.cMapPacked = true; +} var mozL10n = document.mozL10n || document.webL10n; var CSS_UNITS = 96.0 / 72.0; var DEFAULT_SCALE_VALUE = 'auto'; var DEFAULT_SCALE = 1.0; var UNKNOWN_SCALE = 0; @@ -3434,51 +3436,49 @@ var TEXT_LAYER_RENDER_DELAY = 200; // ms /** * @typedef {Object} PDFPageViewOptions * @property {HTMLDivElement} container - The viewer element. * @property {number} id - The page unique ID (normally its number). * @property {number} scale - The page scale display. * @property {PageViewport} defaultViewport - The page viewport. * @property {PDFRenderingQueue} renderingQueue - The rendering queue object. * @property {IPDFTextLayerFactory} textLayerFactory - * @property {IPDFAnnotationsLayerFactory} annotationsLayerFactory + * @property {IPDFAnnotationLayerFactory} annotationLayerFactory */ /** * @class * @implements {IRenderableView} */ var PDFPageView = (function PDFPageViewClosure() { - var CustomStyle = PDFJS.CustomStyle; - /** * @constructs PDFPageView * @param {PDFPageViewOptions} options */ function PDFPageView(options) { var container = options.container; var id = options.id; var scale = options.scale; var defaultViewport = options.defaultViewport; var renderingQueue = options.renderingQueue; var textLayerFactory = options.textLayerFactory; - var annotationsLayerFactory = options.annotationsLayerFactory; + var annotationLayerFactory = options.annotationLayerFactory; this.id = id; this.renderingId = 'page' + id; this.rotation = 0; this.scale = scale || DEFAULT_SCALE; this.viewport = defaultViewport; this.pdfPageRotate = defaultViewport.rotation; this.hasRestrictedScaling = false; this.renderingQueue = renderingQueue; this.textLayerFactory = textLayerFactory; - this.annotationsLayerFactory = annotationsLayerFactory; + this.annotationLayerFactory = annotationLayerFactory; this.renderingState = RenderingStates.INITIAL; this.resume = null; this.onBeforeDraw = null; this.onAfterDraw = null; this.textLayer = null; @@ -3617,16 +3617,18 @@ var PDFPageView = (function PDFPageViewC */ updatePosition: function PDFPageView_updatePosition() { if (this.textLayer) { this.textLayer.render(TEXT_LAYER_RENDER_DELAY); } }, cssTransform: function PDFPageView_transform(canvas, redrawAnnotations) { + var CustomStyle = PDFJS.CustomStyle; + // Scale canvas, canvas wrapper, and page container. var width = this.viewport.width; var height = this.viewport.height; var div = this.div; canvas.style.width = canvas.parentNode.style.width = div.style.width = Math.floor(width) + 'px'; canvas.style.height = canvas.parentNode.style.height = div.style.height = Math.floor(height) + 'px'; @@ -3897,32 +3899,33 @@ var PDFPageView = (function PDFPageViewC ); } }, function pdfPageRenderError(error) { pageViewDrawCallback(error); } ); - if (this.annotationsLayerFactory) { + if (this.annotationLayerFactory) { if (!this.annotationLayer) { - this.annotationLayer = this.annotationsLayerFactory. - createAnnotationsLayerBuilder(div, this.pdfPage); + this.annotationLayer = this.annotationLayerFactory. + createAnnotationLayerBuilder(div, this.pdfPage); } this.annotationLayer.render(this.viewport, 'display'); } div.setAttribute('data-loaded', true); if (self.onBeforeDraw) { self.onBeforeDraw(); } return promise; }, beforePrint: function PDFPageView_beforePrint() { + var CustomStyle = PDFJS.CustomStyle; var pdfPage = this.pdfPage; var viewport = pdfPage.getViewport(1); // Use the same hack we use for high dpi displays for printing to get // better output until bug 811002 is fixed in FF. var PRINT_OUTPUT_SCALE = 2; var canvas = document.createElement('canvas'); @@ -4291,102 +4294,109 @@ DefaultTextLayerFactory.prototype = { pageIndex: pageIndex, viewport: viewport }); } }; /** - * @typedef {Object} AnnotationsLayerBuilderOptions + * @typedef {Object} AnnotationLayerBuilderOptions * @property {HTMLDivElement} pageDiv * @property {PDFPage} pdfPage * @property {IPDFLinkService} linkService */ /** * @class */ -var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() { +var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() { /** - * @param {AnnotationsLayerBuilderOptions} options - * @constructs AnnotationsLayerBuilder + * @param {AnnotationLayerBuilderOptions} options + * @constructs AnnotationLayerBuilder */ - function AnnotationsLayerBuilder(options) { + function AnnotationLayerBuilder(options) { this.pageDiv = options.pageDiv; this.pdfPage = options.pdfPage; this.linkService = options.linkService; this.div = null; } - AnnotationsLayerBuilder.prototype = - /** @lends AnnotationsLayerBuilder.prototype */ { + AnnotationLayerBuilder.prototype = + /** @lends AnnotationLayerBuilder.prototype */ { /** * @param {PageViewport} viewport * @param {string} intent (default value is 'display') */ - render: function AnnotationsLayerBuilder_render(viewport, intent) { + render: function AnnotationLayerBuilder_render(viewport, intent) { var self = this; var parameters = { intent: (intent === undefined ? 'display' : intent), }; this.pdfPage.getAnnotations(parameters).then(function (annotations) { viewport = viewport.clone({ dontFlip: true }); + parameters = { + viewport: viewport, + div: self.div, + annotations: annotations, + page: self.pdfPage, + linkService: self.linkService + }; if (self.div) { // If an annotationLayer already exists, refresh its children's // transformation matrices. - PDFJS.AnnotationLayer.update(viewport, self.div, annotations); + PDFJS.AnnotationLayer.update(parameters); } else { // Create an annotation layer div and render the annotations // if there is at least one annotation. if (annotations.length === 0) { return; } self.div = document.createElement('div'); self.div.className = 'annotationLayer'; self.pageDiv.appendChild(self.div); - - PDFJS.AnnotationLayer.render(viewport, self.div, annotations, - self.pdfPage, self.linkService); + parameters.div = self.div; + + PDFJS.AnnotationLayer.render(parameters); if (typeof mozL10n !== 'undefined') { mozL10n.translate(self.div); } } }); }, - hide: function AnnotationsLayerBuilder_hide() { + hide: function AnnotationLayerBuilder_hide() { if (!this.div) { return; } this.div.setAttribute('hidden', 'true'); } }; - return AnnotationsLayerBuilder; + return AnnotationLayerBuilder; })(); /** * @constructor - * @implements IPDFAnnotationsLayerFactory + * @implements IPDFAnnotationLayerFactory */ -function DefaultAnnotationsLayerFactory() {} -DefaultAnnotationsLayerFactory.prototype = { +function DefaultAnnotationLayerFactory() {} +DefaultAnnotationLayerFactory.prototype = { /** * @param {HTMLDivElement} pageDiv * @param {PDFPage} pdfPage - * @returns {AnnotationsLayerBuilder} + * @returns {AnnotationLayerBuilder} */ - createAnnotationsLayerBuilder: function (pageDiv, pdfPage) { - return new AnnotationsLayerBuilder({ + createAnnotationLayerBuilder: function (pageDiv, pdfPage) { + return new AnnotationLayerBuilder({ pageDiv: pageDiv, pdfPage: pdfPage, linkService: new SimpleLinkService(), }); } }; @@ -4644,17 +4654,17 @@ var PDFViewer = (function pdfViewer() { } var pageView = new PDFPageView({ container: this.viewer, id: pageNum, scale: scale, defaultViewport: viewport.clone(), renderingQueue: this.renderingQueue, textLayerFactory: textLayerFactory, - annotationsLayerFactory: this + annotationLayerFactory: this }); bindOnAfterAndBeforeDraw(pageView); this._pages.push(pageView); } var linkService = this.linkService; // Fetch all the pages since the viewport is needed before printing @@ -5101,20 +5111,20 @@ var PDFViewer = (function pdfViewer() { viewport: viewport, findController: this.isInPresentationMode ? null : this.findController }); }, /** * @param {HTMLDivElement} pageDiv * @param {PDFPage} pdfPage - * @returns {AnnotationsLayerBuilder} + * @returns {AnnotationLayerBuilder} */ - createAnnotationsLayerBuilder: function (pageDiv, pdfPage) { - return new AnnotationsLayerBuilder({ + createAnnotationLayerBuilder: function (pageDiv, pdfPage) { + return new AnnotationLayerBuilder({ pageDiv: pageDiv, pdfPage: pdfPage, linkService: this.linkService }); }, setFindController: function (findController) { this.findController = findController; @@ -7085,17 +7095,18 @@ var PDFViewerApplication = { return; } this.pdfPresentationMode.mouseScroll(delta); } }; function webViewerLoad(evt) { - PDFViewerApplication.initialize().then(webViewerInitialized); + configure(PDFJS); + PDFViewerApplication.initialize().then(webViewerInitialized); } function webViewerInitialized() { var file = window.location.href.split('#')[0]; document.getElementById('openFile').setAttribute('hidden', 'true'); document.getElementById('secondaryOpenFile').setAttribute('hidden', 'true');
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/bootstrap.js @@ -0,0 +1,502 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://services-common/utils.js"); +Cu.import("resource://gre/modules/Preferences.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", + "resource:///modules/RecentWindow.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", + "resource:///modules/CustomizableUI.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "SocialService", + "resource://gre/modules/SocialService.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", + "resource://gre/modules/AddonManager.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", + "resource://gre/modules/ReaderMode.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Pocket", + "chrome://pocket/content/Pocket.jsm"); +XPCOMUtils.defineLazyGetter(this, "gPocketBundle", function() { + return Services.strings.createBundle("chrome://pocket/locale/pocket.properties"); +}); + + +const PREF_BRANCH = "extensions.pocket."; +const PREFS = { + enabled: true, // bug 1229937, figure out ui tour support + api: "api.getpocket.com", + site: "getpocket.com", + oAuthConsumerKey: "40249-e88c401e1b1f2242d9e441c4" +}; + +function setDefaultPrefs() { + let branch = Services.prefs.getDefaultBranch(PREF_BRANCH); + for (let [key, val] in Iterator(PREFS)) { + switch (typeof val) { + case "boolean": + branch.setBoolPref(key, val); + break; + case "number": + branch.setIntPref(key, val); + break; + case "string": + branch.setCharPref(key, val); + break; + } + } +} + +function* allBrowserWindows() { + var winEnum = Services.wm.getEnumerator("navigator:browser"); + while (winEnum.hasMoreElements()) { + let win = winEnum.getNext(); + // skip closed windows + if (win.closed) + continue; + yield win; + } +} + +function createElementWithAttrs(document, type, attrs) { + let element = document.createElement(type); + Object.keys(attrs).forEach(function (attr) { + element.setAttribute(attr, attrs[attr]); + }) + return element; +} + +function CreatePocketWidget(reason) { + let id = "pocket-button" + let widget = CustomizableUI.getWidget(id); + // The widget is only null if we've created then destroyed the widget. + // Once we've actually called createWidget the provider will be set to + // PROVIDER_API. + if (widget && widget.provider == CustomizableUI.PROVIDER_API) + return; + // if upgrading from builtin version and the button was placed in ui, + // seenWidget will not be null + let seenWidget = CustomizableUI.getPlacementOfWidget("pocket-button", false, true); + let pocketButton = { + id: "pocket-button", + defaultArea: CustomizableUI.AREA_NAVBAR, + introducedInVersion: "pref", + type: "view", + viewId: "PanelUI-pocketView", + label: gPocketBundle.GetStringFromName("pocket-button.label"), + tooltiptext: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"), + // Use forwarding functions here to avoid loading Pocket.jsm on startup: + onViewShowing: function() { + return Pocket.onPanelViewShowing.apply(this, arguments); + }, + onViewHiding: function() { + return Pocket.onPanelViewHiding.apply(this, arguments); + }, + onBeforeCreated: function(doc) { + // Bug 1223127,CUI should make this easier to do. + if (doc.getElementById("PanelUI-pocketView")) + return; + let view = doc.createElement("panelview"); + view.id = "PanelUI-pocketView"; + let panel = doc.createElement("vbox"); + panel.setAttribute("class", "panel-subview-body"); + view.appendChild(panel); + doc.getElementById("PanelUI-multiView").appendChild(view); + } + }; + + CustomizableUI.createWidget(pocketButton); + CustomizableUI.addListener(pocketButton); + // placed is null if location is palette + let placed = CustomizableUI.getPlacementOfWidget("pocket-button"); + + // a first time install will always have placed the button somewhere, and will + // not have a placement prior to creating the widget. Thus, !seenWidget && + // placed. + if (reason == ADDON_ENABLE && !seenWidget && placed) { + // initially place the button after the bookmarks button if it is in the UI + let widgets = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR); + let bmbtn = widgets.indexOf("bookmarks-menu-button"); + if (bmbtn > -1) { + CustomizableUI.moveWidgetWithinArea("pocket-button", bmbtn + 1); + } + } + + // Uninstall the Pocket social provider if it exists, but only if we haven't + // already uninstalled it in this manner. That way the user can reinstall + // it if they prefer it without its being uninstalled every time they start + // the browser. + let origin = "https://getpocket.com"; + SocialService.getProvider(origin, provider => { + if (provider) { + let pref = "social.backup.getpocket-com"; + if (!Services.prefs.prefHasUserValue(pref)) { + let str = Cc["@mozilla.org/supports-string;1"]. + createInstance(Ci.nsISupportsString); + str.data = JSON.stringify(provider.manifest); + Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); + SocialService.uninstallProvider(origin, () => {}); + } + } + }); + +}; + +// PocketContextMenu +// When the context menu is opened check if we need to build and enable pocket UI. +var PocketContextMenu = { + init: function() { + Services.obs.addObserver(this, "on-build-contextmenu", false); + }, + shutdown: function() { + Services.obs.removeObserver(this, "on-build-contextmenu"); + // loop through windows and remove context menus + // iterate through all windows and add pocket to them + for (let win of allBrowserWindows()) { + let document = win.document; + for (let id in ["context-pocket", "context-savelinktopocket"]) { + let element = document.getElementById(id); + if (element) + element.remove(); + } + } + }, + observe: function(aSubject, aTopic, aData) { + let subject = aSubject.wrappedJSObject;; + let document = subject.menu.ownerDocument; + let window = document.defaultView; + let pocketEnabled = CustomizableUI.getPlacementOfWidget("pocket-button"); + + let showSaveCurrentPageToPocket = !(subject.onTextInput || subject.onLink || + subject.isContentSelected || subject.onImage || + subject.onCanvas || subject.onVideo || subject.onAudio); + let targetUrl = subject.onLink ? subject.linkUrl : subject.pageUrl; + let targetURI = Services.io.newURI(targetUrl, null, null); + let canPocket = pocketEnabled && (targetURI.schemeIs("http") || targetURI.schemeIs("https") || + (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetUrl))); + + let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket && subject.onLink; + + // create menu entries if necessary + let menu = document.getElementById("context-pocket"); + if (!menu) { + menu = createElementWithAttrs(document, "menuitem", { + "id": "context-pocket", + "label": gPocketBundle.GetStringFromName("saveToPocketCmd.label"), + "accesskey": gPocketBundle.GetStringFromName("saveToPocketCmd.accesskey"), + "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.browser.currentURI.spec, gContextMenu.browser.contentTitle);" + }); + let sibling = document.getElementById("context-savepage"); + if (sibling.nextSibling) { + sibling.parentNode.insertBefore(menu, sibling.nextSibling); + } else { + sibling.parentNode.appendChild(menu); + } + } + menu.hidden = !(canPocket && showSaveCurrentPageToPocket); + + menu = document.getElementById("context-savelinktopocket"); + if (!menu) { + menu = createElementWithAttrs(document, "menuitem", { + "id": "context-savelinktopocket", + "label": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.label"), + "accesskey": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.accesskey"), + "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.linkURL);" + }); + sibling = document.getElementById("context-savelink"); + if (sibling.nextSibling) { + sibling.parentNode.insertBefore(menu, sibling.nextSibling); + } else { + sibling.parentNode.appendChild(menu); + } + } + menu.hidden = !showSaveLinkToPocket; + } +} + +// PocketReader +// Listen for reader mode setup and add our button to the reader toolbar +var PocketReader = { + startup: function() { + let mm = Services.mm; + mm.addMessageListener("Reader:OnSetup", this); + mm.addMessageListener("Reader:Clicked-pocket-button", this); + mm.broadcastAsyncMessage("Reader:AddButton", + { id: "pocket-button", + title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"), + image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark" }); + }, + shutdown: function() { + let mm = Services.mm; + mm.removeMessageListener("Reader:OnSetup", this); + mm.removeMessageListener("Reader:Clicked-pocket-button", this); + mm.broadcastAsyncMessage("Reader:RemoveButton", { id: "pocket-button" }); + }, + receiveMessage: function(message) { + switch (message.name) { + case "Reader:OnSetup": { + // tell the reader about our button. A chrome url here doesn't work, but + // we can use the resoure url. + message.target.messageManager. + sendAsyncMessage("Reader:AddButton", { id: "pocket-button", + title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"), + image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark"}); + break; + } + case "Reader:Clicked-pocket-button": { + let doc = message.target.ownerDocument; + let pocketWidget = doc.getElementById("pocket-button"); + let placement = CustomizableUI.getPlacementOfWidget("pocket-button"); + if (placement) { + if (placement.area == CustomizableUI.AREA_PANEL) { + doc.defaultView.PanelUI.show().then(function() { + // The DOM node might not exist yet if the panel wasn't opened before. + pocketWidget = doc.getElementById("pocket-button"); + pocketWidget.doCommand(); + }); + } else { + pocketWidget.doCommand(); + } + } + break; + } + } + } +} + + +function pktUIGetter(prop, window) { + return { + get: function() { + // delete any getters for properties loaded from main.js so we only load main.js once + delete window.pktUI; + delete window.pktUIMessaging; + Services.scriptloader.loadSubScript("chrome://pocket/content/main.js", window); + return window[prop]; + }, + configurable: true, + enumerable: true + }; +} + +var PocketOverlay = { + startup: function(reason) { + this.registerStylesheet(); + CreatePocketWidget(reason); + Services.obs.addObserver(this, + "browser-delayed-startup-finished", + false); + CustomizableUI.addListener(this); + PocketContextMenu.init(); + PocketReader.startup(); + + if (reason == ADDON_ENABLE) { + for (let win of allBrowserWindows()) { + this.setWindowScripts(win); + this.updateWindow(win); + } + } + }, + shutdown: function(reason) { + CustomizableUI.removeListener(this); + for (let window of allBrowserWindows()) { + for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket", + "panelMenu_pocketSeparator", "menu_pocketSeparator", + "BMB_pocketSeparator"]) { + let element = window.document.getElementById(id); + if (element) + element.remove(); + } + // remove script getters/objects + delete window.Pocket; + delete window.pktUI; + delete window.pktUIMessaging; + } + CustomizableUI.destroyWidget("pocket-button"); + PocketContextMenu.shutdown(); + PocketReader.shutdown(); + this.unregisterStylesheet(); + }, + observe: function(aSubject, aTopic, aData) { + // new browser window, initialize the "overlay" + let window = aSubject; + this.setWindowScripts(window); + this.updateWindow(window); + }, + setWindowScripts: function(window) { + XPCOMUtils.defineLazyModuleGetter(window, "Pocket", + "chrome://pocket/content/Pocket.jsm"); + // Can't use XPCOMUtils for these because the scripts try to define the variables + // on window, and so the defineProperty inside defineLazyGetter fails. + Object.defineProperty(window, "pktUI", pktUIGetter("pktUI", window)); + Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging", window)); + }, + // called for each window as it is opened + updateWindow: function(window) { + // insert our three menu items + let document = window.document; + + // add to bookmarksMenu + let sib = document.getElementById("menu_bookmarkThisPage"); + if (sib && !document.getElementById("menu_pocket")) { + let menu = createElementWithAttrs(document, "menuitem", { + "id": "menu_pocket", + "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"), + "class": "menuitem-iconic", // OSX only + "oncommand": "openUILink(Pocket.listURL, event);" + }); + let sep = createElementWithAttrs(document, "menuseparator", { + "id": "menu_pocketSeparator" + }); + sib.parentNode.insertBefore(menu, sib); + sib.parentNode.insertBefore(sep, sib); + } + + // add to bookmarks-menu-button + sib = document.getElementById("BMB_subscribeToPageMenuitem"); + if (sib && !document.getElementById("BMB_pocket")) { + let menu = createElementWithAttrs(document, "menuitem", { + "id": "BMB_pocket", + "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"), + "class": "menuitem-iconic bookmark-item subviewbutton", + "oncommand": "openUILink(Pocket.listURL, event);" + }); + let sep = createElementWithAttrs(document, "menuseparator", { + "id": "BMB_pocketSeparator" + }); + sib.parentNode.insertBefore(menu, sib); + sib.parentNode.insertBefore(sep, sib); + } + + // add to PanelUI-bookmarks + sib = document.getElementById("panelMenuBookmarkThisPage"); + if (sib && !document.getElementById("panelMenu_pocket")) { + let menu = createElementWithAttrs(document, "toolbarbutton", { + "id": "panelMenu_pocket", + "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"), + "class": "subviewbutton cui-withicon", + "oncommand": "openUILink(Pocket.listURL, event);" + }); + let sep = createElementWithAttrs(document, "toolbarseparator", { + "id": "panelMenu_pocketSeparator" + }); + // nextSibling is no-id toolbarseparator + // insert separator first then button + sib = sib.nextSibling; + sib.parentNode.insertBefore(sep, sib); + sib.parentNode.insertBefore(menu, sib); + } + + this.updatePocketItemVisibility(document); + }, + onWidgetAdded: function(aWidgetId, aArea, aPosition) { + for (let win of allBrowserWindows()) { + this.updatePocketItemVisibility(win.document); + } + }, + onWidgetRemoved: function(aWidgetId, aArea, aPosition) { + for (let win of allBrowserWindows()) { + this.updatePocketItemVisibility(win.document); + } + }, + onWidgetReset: function(aNode, aContainer) { + // CUI was reset and doesn't respect default area for API widgets, place our + // widget back to the default area + // initially place the button after the bookmarks button if it is in the UI + let widgets = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR); + let bmbtn = widgets.indexOf("bookmarks-menu-button"); + if (bmbtn > -1) { + CustomizableUI.addWidgetToArea("pocket-button", CustomizableUI.AREA_NAVBAR, bmbtn + 1); + } else { + CustomizableUI.addWidgetToArea("pocket-button", CustomizableUI.AREA_NAVBAR); + } + }, + updatePocketItemVisibility: function(doc) { + let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button"); + for (let prefix of ["panelMenu_", "menu_", "BMB_"]) { + let element = doc.getElementById(prefix + "pocket"); + if (element) { + element.hidden = hidden; + doc.getElementById(prefix + "pocketSeparator").hidden = hidden; + } + } + // enable or disable reader button + if (hidden) { + PocketReader.shutdown(); + } else { + PocketReader.startup(); + } + }, + + registerStylesheet: function() { + let styleSheetService= Components.classes["@mozilla.org/content/style-sheet-service;1"] + .getService(Components.interfaces.nsIStyleSheetService); + let styleSheetURI = Services.io.newURI("chrome://pocket/skin/pocket.css", null, null); + styleSheetService.loadAndRegisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET); + styleSheetURI = Services.io.newURI("chrome://pocket-shared/skin/pocket.css", null, null); + styleSheetService.loadAndRegisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET); + }, + + unregisterStylesheet: function() { + let styleSheetService = Components.classes["@mozilla.org/content/style-sheet-service;1"] + .getService(Components.interfaces.nsIStyleSheetService); + let styleSheetURI = Services.io.newURI("chrome://pocket/skin/pocket.css", null, null); + if (styleSheetService.sheetRegistered(styleSheetURI, styleSheetService.AUTHOR_SHEET)) { + styleSheetService.unregisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET); + } + styleSheetURI = Services.io.newURI("chrome://pocket-shared/skin/pocket.css", null, null); + if (styleSheetService.sheetRegistered(styleSheetURI, styleSheetService.AUTHOR_SHEET)) { + styleSheetService.unregisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET); + } + } + +} + +// use enabled pref as a way for tests (e.g. test_contextmenu.html) to disable +// the addon when running. +function prefObserver(aSubject, aTopic, aData) { + let enabled = Services.prefs.getBoolPref("extensions.pocket.enabled"); + if (enabled) + PocketOverlay.startup(ADDON_ENABLE); + else + PocketOverlay.shutdown(ADDON_DISABLE); +} + +function startup(data, reason) { + AddonManager.getAddonByID("isreaditlater@ideashower.com", addon => { + if (addon && addon.isActive) + return; + setDefaultPrefs(); + // migrate enabled pref + if (Services.prefs.prefHasUserValue("browser.pocket.enabled")) { + Services.prefs.setBoolPref("extensions.pocket.enabled", Services.prefs.getBoolPref("browser.pocket.enabled")); + Services.prefs.clearUserPref("browser.pocket.enabled"); + } + // watch pref change and enable/disable if necessary + Services.prefs.addObserver("extensions.pocket.enabled", prefObserver, false); + if (Services.prefs.prefHasUserValue("extensions.pocket.enabled") && + !Services.prefs.getBoolPref("extensions.pocket.enabled")) + return; + PocketOverlay.startup(reason); + }); +} + +function shutdown(data, reason) { + // For speed sake, we should only do a shutdown if we're being disabled. + // On an app shutdown, just let it fade away... + if (reason == ADDON_DISABLE) { + Services.prefs.removeObserver("extensions.pocket.enabled", prefObserver); + PocketOverlay.shutdown(reason); + } +} + +function install() { +} + +function uninstall() { +}
rename from browser/components/pocket/Pocket.jsm rename to browser/extensions/pocket/content/Pocket.jsm --- a/browser/components/pocket/Pocket.jsm +++ b/browser/extensions/pocket/content/Pocket.jsm @@ -11,17 +11,17 @@ Cu.import("resource://gre/modules/XPCOMU Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); var Pocket = { - get site() { return Services.prefs.getCharPref("browser.pocket.site"); }, + get site() { return Services.prefs.getCharPref("extensions.pocket.site"); }, get listURL() { return "https://" + Pocket.site + "/?src=ff_ext"; }, /** * Functions related to the Pocket panel UI. */ onPanelViewShowing(event) { let document = event.target.ownerDocument; let window = document.defaultView; @@ -32,17 +32,17 @@ var Pocket = { Pocket._urlToSave = null; Pocket._titleToSave = null; // ViewShowing fires immediately before it creates the contents, // in lieu of an AfterViewShowing event, just spin the event loop. window.setTimeout(function() { if (urlToSave) { window.pktUI.tryToSaveUrl(urlToSave, titleToSave); } else { - window.pktUI.pocketButtonOnCommand(); + window.pktUI.tryToSaveCurrentPage(); } if (iframe.contentDocument && iframe.contentDocument.readyState == "complete") { window.pktUI.pocketPanelDidShow(); } else { // iframe didn't load yet. This seems to always be the case when in // the toolbar panel, but never the case for a subview.
rename from browser/components/pocket/main.js rename to browser/extensions/pocket/content/main.js --- a/browser/components/pocket/main.js +++ b/browser/extensions/pocket/content/main.js @@ -10,20 +10,20 @@ * SOFTWARE * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ @@ -41,238 +41,79 @@ // TODO : [needs clarificaiton from Fx] Move prefs within pktApi.s to sqlite or a local file so it's not editable (and is safer) // TODO : [nice to have] - Immediately save, buffer the actions in a local queue and send (so it works offline, works like our native extensions) Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "pktApi", + "chrome://pocket/content/pktApi.jsm"); var pktUI = (function() { // -- Initialization (on startup and new windows) -- // var inited = false; var _currentPanelDidShow; var _currentPanelDidHide; var _isHidden = false; var _notificationTimeout; // Init panel id at 0. The first actual panel id will have the number 1 so // in case at some point any panel has the id 0 we know there is something // wrong var _panelId = 0; - var prefBranch = Services.prefs.getBranch("browser.pocket.settings."); + var prefBranch = Services.prefs.getBranch("extensions.pocket.settings."); var overflowMenuWidth = 230; var overflowMenuHeight = 475; var savePanelWidth = 350; var savePanelHeights = {collapsed: 153, expanded: 272}; - /** - * Initalizes Pocket UI and panels - */ - function onLoad() { - - if (inited) - return; - - // Install the button (Only on first run, if a user removes the button, you do not want to restore it) - // TODO, only do this if in a certain language - // TODO - Ask Mozilla what the best way is to have this update when a user restores browser defaults - // TODO - this needs to run only on a main window - if the first run happens on a window without the toolbar, then it will never try to run it again - if (!prefBranch.prefHasUserValue('installed')) { - - // If user has social add-on installed, uninstall it - if (Social.getManifestByOrigin("https://getpocket.com")) { - Social.uninstallProvider("https://getpocket.com", function(){ /* callback */ }); - } - - // if user has legacy pkt add-on installed, flag it so we can handle it correctly - prefBranch.setBoolPref('hasLegacyExtension', hasLegacyExtension()); - - var id = "pocket-menu-button"; - var toolbar = document.getElementById("nav-bar"); - - var before = null; - // Is the bookmarks button in the toolbar? - if (toolbar.currentSet.match("bookmarks-menu-button")) { - var elem = document.getElementById("bookmarks-menu-button"); - if (elem) - before = elem.nextElementSibling; - } - // Otherwise, just add it to the end of the toolbar (because before is null) - - toolbar.insertItem(id, before); - - toolbar.setAttribute("currentset", toolbar.currentSet); - document.persist(toolbar.id, "currentset"); - - prefBranch.setBoolPref('installed', true); - } - - // Context Menu Event - document.getElementById('contentAreaContextMenu').addEventListener("popupshowing", contextOnPopupShowing, false); - - // Hide the extension based on certain criteria - hideIntegrationIfNeeded(); - - inited = true; - } - - /** - * Mark all Pocket integration chrome elements as hidden if certain criteria apply (ex: legacy Pocket extension users or unsupported languages) - */ - function hideIntegrationIfNeeded() { - - var hideIntegration = false; - - // Check if the user had the legacy extension the last time we looked - if (prefBranch.getBoolPref('hasLegacyExtension')) { - if (hasLegacyExtension()) { - hideIntegration = true; // they still have it, hide new native integration - } - else { - // if they originally had it, but no longer do, then we should remove the pref so we no longer have to check - prefBranch.setBoolPref('hasLegacyExtension', false); - } - } - - // TODO - // If language other than launch languages (en-US currently) { - // hideIntegration = true; - //} - - // Hide the integration if needed - if (hideIntegration) { - // Note, we don't hide the context menus here, that's handled in contextOnPopupShowing - var elements = ['pocket-menu-button', 'BMB_openPocketWebapp']; - for(var i=0; i<elements.length; i++) { - document.getElementById(elements[i]).setAttribute('hidden', true); - } - - _isHidden = true; - } - else - _isHidden = false - } - - // -- Event Handling -- // - + /** * Event handler when Pocket toolbar button is pressed */ - function pocketButtonOnCommand(event) { - - tryToSaveCurrentPage(); - - } - + function pocketPanelDidShow(event) { if (_currentPanelDidShow) { _currentPanelDidShow(event); } - + } - + function pocketPanelDidHide(event) { if (_currentPanelDidHide) { _currentPanelDidHide(event); } - + // clear the panel getPanelFrame().setAttribute('src', 'about:blank'); } /** * Event handler when Pocket bookmark bar entry is pressed */ function pocketBookmarkBarOpenPocketCommand(event) { openTabWithUrl('https://getpocket.com/a/', true); } - /** - * Event handler when Pocket context menu button is presed - */ - - // Determine which context menus to show before it's shown - function contextOnPopupShowing() { - - var saveLinkId = "PKT_context_saveLink"; - var savePageId = "PKT_context_savePage"; - - if (isHidden()) { - gContextMenu.showItem(saveLinkId, false); - gContextMenu.showItem(savePageId, false); - } else if ( (gContextMenu.onSaveableLink || ( gContextMenu.inDirList && gContextMenu.onLink )) ) { - gContextMenu.showItem(saveLinkId, true); - gContextMenu.showItem(savePageId, false); - } else if (gContextMenu.isTextSelected) { - gContextMenu.showItem(saveLinkId, false); - gContextMenu.showItem(savePageId, false); - } else if (!gContextMenu.onTextInput) { - gContextMenu.showItem(saveLinkId, false); - gContextMenu.showItem(savePageId, true); - } else { - gContextMenu.showItem(saveLinkId, false); - gContextMenu.showItem(savePageId, false); - } - } - - function pocketContextSaveLinkOnCommand(event) { - // TODO : Unsafe CPOW Usage when saving with Page context menu (Ask Mozilla for help with this one) - var linkNode = gContextMenu.target || document.popupNode; - - // Get parent node in case of text nodes (old safari versions) - if (linkNode.nodeType == Node.TEXT_NODE) { - linkNode = linkNode.parentNode; - } - - // If for some reason, it's not an element node, abort - if (linkNode.nodeType != Node.ELEMENT_NODE) { - return; - } - - // Try to get a link element in the parent chain as we can be in the - // last child element - var currentElement = linkNode; - while (currentElement !== null) { - if (currentElement.nodeType == Node.ELEMENT_NODE && - currentElement.nodeName.toLowerCase() == 'a') - { - // We have a link element try to save it - linkNode = currentElement; - break; - } - currentElement = currentElement.parentNode; - } - - var link = linkNode.href; - tryToSaveUrl(link); - - event.stopPropagation(); - } - - function pocketContextSavePageOnCommand(event) { - tryToSaveCurrentPage(); - } - - // -- Communication to API -- // /** * Either save or attempt to log the user in */ function tryToSaveCurrentPage() { tryToSaveUrl(getCurrentUrl(), getCurrentTitle()); } - + function tryToSaveUrl(url, title) { // If the user is logged in, go ahead and save the current page if (pktApi.isUserLoggedIn()) { saveAndShowConfirmation(url, title); return; } @@ -287,18 +128,18 @@ var pktUI = (function() { * Show the sign-up panel */ function showSignUp() { getFirefoxAccountSignedInUser(function(userdata) { var fxasignedin = (typeof userdata == 'object' && userdata !== null) ? '1' : '0'; var startheight = 490; var inOverflowMenu = isInOverflowMenu(); - - if (inOverflowMenu) + + if (inOverflowMenu) { startheight = overflowMenuHeight; } else if (pktApi.getSignupAB().indexOf('storyboard') > -1) { startheight = 460; if (fxasignedin == '1') { @@ -316,17 +157,17 @@ var pktUI = (function() { if (inOverflowMenu) { variant = 'overflow'; } else { variant = pktApi.getSignupAB(); } - var panelId = showPanel("about:pocket-signup?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&fxasignedin=" + fxasignedin + "&variant=" + variant + '&inoverflowmenu=' + inOverflowMenu + "&locale=" + getUILocale(), { + var panelId = showPanel("chrome://pocket/content/panels/signup.html?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&fxasignedin=" + fxasignedin + "&variant=" + variant + '&inoverflowmenu=' + inOverflowMenu + "&locale=" + getUILocale(), { onShow: function() { }, onHide: panelDidHide, width: inOverflowMenu ? overflowMenuWidth : 300, height: startheight }); }); } @@ -344,17 +185,17 @@ var pktUI = (function() { var isValidURL = (typeof url !== 'undefined' && (url.startsWith("http") || url.startsWith('https'))); var inOverflowMenu = isInOverflowMenu(); var startheight = pktApi.isPremiumUser() && isValidURL ? savePanelHeights.expanded : savePanelHeights.collapsed; if (inOverflowMenu) { startheight = overflowMenuHeight; } - var panelId = showPanel("about:pocket-saved?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0') + '&inoverflowmenu='+inOverflowMenu + "&locale=" + getUILocale(), { + var panelId = showPanel("chrome://pocket/content/panels/saved.html?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0') + '&inoverflowmenu='+inOverflowMenu + "&locale=" + getUILocale(), { onShow: function() { var saveLinkMessageId = 'saveLink'; // Send error message for invalid url if (!isValidURL) { // TODO: Pass key for localized error in error object var error = { message: 'Only links can be saved', @@ -474,17 +315,17 @@ var pktUI = (function() { iframe.style.height = options.height + "px"; } } /** * Called when the signup and saved panel was hidden */ function panelDidHide() { - + } /** * Register all of the messages needed for the panels */ function registerEventMessages() { var iframe = getPanelFrame(); @@ -610,17 +451,17 @@ var pktUI = (function() { pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _deleteItemMessageId, error); } }) }); var _initL10NMessageId = "initL10N"; pktUIMessaging.addMessageListener(_initL10NMessageId, function(panelId, data) { var strings = {}; - var bundle = Services.strings.createBundle("chrome://browser/locale/browser-pocket.properties"); + var bundle = Services.strings.createBundle("chrome://pocket/locale/pocket.properties"); var e = bundle.getSimpleEnumeration(); while(e.hasMoreElements()) { var str = e.getNext().QueryInterface(Components.interfaces.nsIPropertyElement); strings[str.key] = str.value; } pktUIMessaging.sendResponseMessageToPanel(panelId, _initL10NMessageId, { strings: strings }); }); @@ -720,130 +561,37 @@ var pktUI = (function() { function getFirefoxAccountSignedInUser(callback) { fxAccounts.getSignedInUser().then(userData => { callback(userData); }).then(null, error => { callback(); }); } - + function getUILocale() { var locale = Cc["@mozilla.org/chrome/chrome-registry;1"]. getService(Ci.nsIXULChromeRegistry). getSelectedLocale("browser"); return locale; } - /** - * Toolbar animations - */ - - function showPocketAnimation() { - - // Borrowed from bookmark star animation: - // https://dxr.mozilla.org/mozilla-central/source/browser/base/content/browser-places.js#1568 - - // TODO : Clean-up : Probably don't need all of this since the css animation does most of the heavy lifting - // TODO : Do not show when saving from context menu -- or get really fancy and launch the icon from the link that was saved into the bookmark menu - - function getCenteringTransformForRects(rectToPosition, referenceRect) { - let topDiff = referenceRect.top - rectToPosition.top; - let leftDiff = referenceRect.left - rectToPosition.left; - let heightDiff = referenceRect.height - rectToPosition.height; - let widthDiff = referenceRect.width - rectToPosition.width; - return [(leftDiff + .5 * widthDiff) + "px", (topDiff + .5 * heightDiff) + "px"]; - } - - if (_notificationTimeout) { - clearTimeout(this._notificationTimeout); - } - - var button = document.getElementById('pocket-menu-button'); - var bookmarksButton = document.getElementById('bookmarks-menu-button'); - var notifier = document.getElementById("pocketed-notification-anchor"); - var dropmarkerNotifier = document.getElementById("bookmarked-notification-dropmarker-anchor"); - - - // If the Pocket button is not immediately after the bookmark button, then do not do the animation - // (because it's hard-coded for the positions right now) - // TODO - double check this in small and large toolbar button sizes - if (bookmarksButton.nextElementSibling != button) - return; - - if (notifier.style.transform == '') { - // Get all the relevant nodes and computed style objects - let dropmarker = document.getAnonymousElementByAttribute(bookmarksButton, "anonid", "dropmarker"); - let dropmarkerIcon = document.getAnonymousElementByAttribute(dropmarker, "class", "dropmarker-icon"); - let dropmarkerStyle = getComputedStyle(dropmarkerIcon); - - // Check for RTL and get bounds - let isRTL = getComputedStyle(button).direction == "rtl"; // need this? - let buttonRect = button.getBoundingClientRect(); - let notifierRect = notifier.getBoundingClientRect(); - let dropmarkerRect = dropmarkerIcon.getBoundingClientRect(); - let dropmarkerNotifierRect = dropmarkerNotifier.getBoundingClientRect(); - - // Compute, but do not set, transform for pocket icon - let [translateX, translateY] = getCenteringTransformForRects(notifierRect, buttonRect); - let starIconTransform = "translate(" + (translateX) + ", " + translateY + ")"; - if (isRTL) { - starIconTransform += " scaleX(-1)"; - } - - // Compute, but do not set, transform for dropmarker - [translateX, translateY] = getCenteringTransformForRects(dropmarkerNotifierRect, dropmarkerRect); - let dropmarkerTransform = "translate(" + translateX + ", " + translateY + ")"; - - // Do all layout invalidation in one go: - notifier.style.transform = starIconTransform; - dropmarkerNotifier.style.transform = dropmarkerTransform; - - let dropmarkerAnimationNode = dropmarkerNotifier.firstChild; - dropmarkerAnimationNode.style.MozImageRegion = dropmarkerStyle.MozImageRegion; - dropmarkerAnimationNode.style.listStyleImage = dropmarkerStyle.listStyleImage; - } - - let isInOverflowMenu = button.getAttribute("overflowedItem") == "true"; - if (!isInOverflowMenu) { - notifier.setAttribute("notification", "finish"); - button.setAttribute("notification", "finish"); - dropmarkerNotifier.setAttribute("notification", "finish"); - } - - _notificationTimeout = setTimeout( () => { - notifier.removeAttribute("notification"); - dropmarkerNotifier.removeAttribute("notification"); - button.removeAttribute("notification"); - - dropmarkerNotifier.style.transform = ''; - notifier.style.transform = ''; - }, 1000); - } - - /** * Public functions */ return { - onLoad: onLoad, getPanelFrame: getPanelFrame, openTabWithUrl: openTabWithUrl, - pocketButtonOnCommand: pocketButtonOnCommand, pocketPanelDidShow: pocketPanelDidShow, pocketPanelDidHide: pocketPanelDidHide, - pocketContextSaveLinkOnCommand, - pocketContextSavePageOnCommand, - - pocketBookmarkBarOpenPocketCommand, - - tryToSaveUrl: tryToSaveUrl + tryToSaveUrl: tryToSaveUrl, + tryToSaveCurrentPage: tryToSaveCurrentPage }; }()); // -- Communication to Background -- // // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages var pktUIMessaging = (function() { /** @@ -852,17 +600,17 @@ var pktUIMessaging = (function() { function prefixedMessageId(messageId) { return 'PKT_' + messageId; } /** * Register a listener and callback for a specific messageId */ function addMessageListener(messageId, callback) { - document.addEventListener(prefixedMessageId(messageId), function(e) { + document.addEventListener(prefixedMessageId(messageId), function(e) { // ignore to ensure we do not pick up other events in the browser if (e.target.tagName !== 'PKTMESSAGEFROMPANELELEMENT') { return; } // Pass in information to callback var payload = JSON.parse(e.target.getAttribute("payload"))[0]; var panelId = payload.panelId;
rename from browser/components/pocket/panels/css/firasans.css rename to browser/extensions/pocket/content/panels/css/firasans.css
rename from browser/components/pocket/panels/css/normalize.css rename to browser/extensions/pocket/content/panels/css/normalize.css
rename from browser/components/pocket/panels/css/saved.css rename to browser/extensions/pocket/content/panels/css/saved.css
rename from browser/components/pocket/panels/css/signup.css rename to browser/extensions/pocket/content/panels/css/signup.css
rename from browser/components/pocket/panels/fonts/FiraSans-Regular.woff rename to browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff
rename from toolkit/themes/shared/reader/pocket.svg rename to browser/extensions/pocket/content/panels/img/pocket.svg
rename from browser/components/pocket/panels/img/pocketerror@1x.png rename to browser/extensions/pocket/content/panels/img/pocketerror@1x.png
rename from browser/components/pocket/panels/img/pocketerror@2x.png rename to browser/extensions/pocket/content/panels/img/pocketerror@2x.png
rename from browser/components/pocket/panels/img/pocketlogo@1x.png rename to browser/extensions/pocket/content/panels/img/pocketlogo@1x.png
rename from browser/components/pocket/panels/img/pocketlogo@2x.png rename to browser/extensions/pocket/content/panels/img/pocketlogo@2x.png
rename from browser/components/pocket/panels/img/pocketlogosolo@1x.png rename to browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png
rename from browser/components/pocket/panels/img/pocketlogosolo@2x.png rename to browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png
rename from browser/components/pocket/panels/img/pocketmenuitem16.png rename to browser/extensions/pocket/content/panels/img/pocketmenuitem16.png
rename from browser/components/pocket/panels/img/pocketmenuitem16@2x.png rename to browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png
rename from browser/components/pocket/panels/img/pocketsignup_button@1x.png rename to browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png
rename from browser/components/pocket/panels/img/pocketsignup_button@2x.png rename to browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png
rename from browser/components/pocket/panels/img/pocketsignup_devices@1x.png rename to browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png
rename from browser/components/pocket/panels/img/pocketsignup_devices@2x.png rename to browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png
rename from browser/components/pocket/panels/img/pocketsignup_hero@1x.png rename to browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png
rename from browser/components/pocket/panels/img/pocketsignup_hero@2x.png rename to browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png
rename from browser/components/pocket/panels/img/signup_firefoxlogo@1x.png rename to browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png
rename from browser/components/pocket/panels/img/signup_firefoxlogo@2x.png rename to browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png
rename from browser/components/pocket/panels/img/signup_help@1x.png rename to browser/extensions/pocket/content/panels/img/signup_help@1x.png
rename from browser/components/pocket/panels/img/signup_help@2x.png rename to browser/extensions/pocket/content/panels/img/signup_help@2x.png
rename from browser/components/pocket/panels/img/signup_or@1x.png rename to browser/extensions/pocket/content/panels/img/signup_or@1x.png
rename from browser/components/pocket/panels/img/signup_or@2x.png rename to browser/extensions/pocket/content/panels/img/signup_or@2x.png
rename from browser/components/pocket/panels/img/tag_close@1x.png rename to browser/extensions/pocket/content/panels/img/tag_close@1x.png
rename from browser/components/pocket/panels/img/tag_close@2x.png rename to browser/extensions/pocket/content/panels/img/tag_close@2x.png
rename from browser/components/pocket/panels/img/tag_closeactive@1x.png rename to browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png
rename from browser/components/pocket/panels/img/tag_closeactive@2x.png rename to browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png
rename from browser/components/pocket/panels/js/messages.js rename to browser/extensions/pocket/content/panels/js/messages.js
rename from browser/components/pocket/panels/js/saved.js rename to browser/extensions/pocket/content/panels/js/saved.js
rename from browser/components/pocket/panels/js/signup.js rename to browser/extensions/pocket/content/panels/js/signup.js
rename from browser/components/pocket/panels/js/tmpl.js rename to browser/extensions/pocket/content/panels/js/tmpl.js
rename from browser/components/pocket/panels/js/vendor/handlebars.runtime.js rename to browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js
rename from browser/components/pocket/panels/js/vendor/jquery-2.1.1.min.js rename to browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js
rename from browser/components/pocket/panels/js/vendor/jquery.tokeninput.min.js rename to browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js
rename from browser/components/pocket/panels/license.txt rename to browser/extensions/pocket/content/panels/license.txt
rename from browser/components/pocket/panels/saved.html rename to browser/extensions/pocket/content/panels/saved.html --- a/browser/components/pocket/panels/saved.html +++ b/browser/extensions/pocket/content/panels/saved.html @@ -1,13 +1,13 @@ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> - <base href="chrome://browser/content/pocket/panels/"> + <base href="chrome://pocket/content/panels/"> <title>Pocket: Page Saved</title> <link rel="stylesheet" href="css/normalize.css"> <link rel="stylesheet" href="css/firasans.css"> <link rel="stylesheet" href="css/saved.css"> </head> <body class="pkt_ext_containersaved" aria-live="polite"> <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script>
rename from browser/components/pocket/panels/signup.html rename to browser/extensions/pocket/content/panels/signup.html --- a/browser/components/pocket/panels/signup.html +++ b/browser/extensions/pocket/content/panels/signup.html @@ -1,13 +1,13 @@ <!DOCTYPE html> <html> <head> <meta charset="utf-8"> - <base href="chrome://browser/content/pocket/panels/"> + <base href="chrome://pocket/content/panels/"> <title>Pocket: Sign Up</title> <link rel="stylesheet" href="css/normalize.css"> <link rel="stylesheet" href="css/firasans.css"> <link rel="stylesheet" href="css/signup.css"> </head> <body class="pkt_ext_containersignup" aria-live="polite"> <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script> <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script>
rename from browser/components/pocket/panels/tmpl/saved_premiumextras.handlebars rename to browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars
rename from browser/components/pocket/panels/tmpl/saved_premiumshell.handlebars rename to browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars
rename from browser/components/pocket/panels/tmpl/saved_shell.handlebars rename to browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars
rename from browser/components/pocket/panels/tmpl/signup_shell.handlebars rename to browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars
rename from browser/components/pocket/panels/tmpl/signupstoryboard_shell.handlebars rename to browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars
rename from browser/components/pocket/pktApi.js rename to browser/extensions/pocket/content/pktApi.jsm --- a/browser/components/pocket/pktApi.js +++ b/browser/extensions/pocket/content/pktApi.jsm @@ -37,37 +37,44 @@ * Definition of keys stored in preferences to preserve user state: * premium_status: Current premium status for logged in user if available * Can be 0 for no premium and 1 for premium * latestSince: Last timestamp a save happened * tags: All tags for logged in user * usedTags: All used tags from within the extension sorted by recency */ +const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components; +this.EXPORTED_SYMBOLS = ["pktApi"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + + var pktApi = (function() { /** * Configuration */ // Base url for all api calls - var pocketAPIhost = Services.prefs.getCharPref("browser.pocket.api"); // api.getpocket.com - var pocketSiteHost = Services.prefs.getCharPref("browser.pocket.site"); // getpocket.com + var pocketAPIhost = Services.prefs.getCharPref("extensions.pocket.api"); // api.getpocket.com + var pocketSiteHost = Services.prefs.getCharPref("extensions.pocket.site"); // getpocket.com var baseAPIUrl = "https://" + pocketAPIhost + "/v3"; /** * Auth keys for the API requests */ - var oAuthConsumerKey = Services.prefs.getCharPref("browser.pocket.oAuthConsumerKey"); + var oAuthConsumerKey = Services.prefs.getCharPref("extensions.pocket.oAuthConsumerKey"); /** * */ - var prefBranch = Services.prefs.getBranch("browser.pocket.settings."); + var prefBranch = Services.prefs.getBranch("extensions.pocket.settings."); /** * Helper */ var extend = function(out) { out = out || {};
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/install.rdf.in @@ -0,0 +1,31 @@ +<?xml version="1.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/. --> + +#filter substitution + +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + + <Description about="urn:mozilla:install-manifest"> + <em:id>firefox@getpocket.com</em:id> + <em:version>@FIREFOX_VERSION@</em:version> + <em:type>2</em:type> + <em:bootstrap>true</em:bootstrap> + + <!-- Target Application this theme can install into, + with minimum and maximum supported versions. --> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>@FIREFOX_VERSION@</em:minVersion> + <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion> + </Description> + </em:targetApplication> + + <!-- Front End MetaData --> + <em:name>Pocket</em:name> + <em:description>When you find something you want to view later, put it in Pocket.</em:description> + </Description> +</RDF>
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/jar.mn @@ -0,0 +1,12 @@ +# 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/. + +[features/firefox@getpocket.com] chrome.jar: +% content pocket %content/ contentaccessible=yes +% skin pocket classic/1.0 %skin/linux/ os=Linux +% skin pocket classic/1.0 %skin/osx/ os=Darwin +% skin pocket classic/1.0 %skin/windows/ os=WINNT +% skin pocket-shared classic/1.0 %skin/shared/ + content/ (content/*) + skin/ (skin/*)
rename from browser/locales/en-US/chrome/browser/browser-pocket.properties rename to browser/extensions/pocket/locales/en-US/pocket.properties --- a/browser/locales/en-US/chrome/browser/browser-pocket.properties +++ b/browser/extensions/pocket/locales/en-US/pocket.properties @@ -24,8 +24,18 @@ signuptosave = Sign up for Pocket. It’s free. suggestedtags = Suggested Tags tagline = Save articles and videos from Firefox to view in Pocket on any device, any time. taglinestory_one = Click the Pocket Button to save any article, video or page from Firefox. taglinestory_two = View in Pocket on any device, any time. tagssaved = Tags Added signinfirefox = Sign in with Firefox signupfirefox = Sign up with Firefox viewlist = View List + +# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): +# "Pocket" is a brand name. +pocket-button.label = Pocket +pocket-button.tooltiptext = Save to Pocket +saveToPocketCmd.label = Save Page to Pocket +saveToPocketCmd.accesskey = k +saveLinkToPocketCmd.label = Save Link to Pocket +saveLinkToPocketCmd.accesskey = o +pocketMenuitem.label = View Pocket List
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/locales/jar.mn @@ -0,0 +1,8 @@ +#filter substitution +# 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/. + +[features/firefox@getpocket.com] @AB_CD@.jar: +% locale pocket @AB_CD@ %locale/@AB_CD@/ + locale/@AB_CD@/ (%*)
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/locales/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; c-basic-offset: 4; 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/. + +JAR_MANIFESTS += ['jar.mn']
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/moz.build @@ -0,0 +1,17 @@ +# -*- Mode: python; c-basic-offset: 4; 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/. + +DIRS += ['locales'] + +FINAL_TARGET_FILES.features['firefox@getpocket.com'] += [ + 'bootstrap.js' +] + +FINAL_TARGET_PP_FILES.features['firefox@getpocket.com'] += [ + 'install.rdf.in' +] + +JAR_MANIFESTS += ['jar.mn']
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/skin/osx/pocket.css @@ -0,0 +1,38 @@ +#pocket-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(36px, 774px, 54px, 756px); +} + +@media (min-resolution: 1.1dppx) { + + #pocket-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 1548px, 36px, 1512px); + } + + #pocket-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(72px, 1548px, 108px, 1512px); + } +} + +@media (min-resolution: 2dppx) { + #panelMenu_pocket, + #menu_pocket, + #BMB_pocket { + list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16@2x.png"); + } + + #panelMenu_pocket > .toolbarbutton-icon { + width: 16px; + } +} + +@media not all and (min-resolution: 1.1dppx) { + #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) { + -moz-image-region: rect(18px, 774px, 36px, 756px); + } +} + +@media (min-resolution: 1.1dppx) { + #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) { + -moz-image-region: rect(36px, 1548px, 72px, 1512px); + } +}
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/skin/shared/pocket.css @@ -0,0 +1,68 @@ +/* Bug 1164419 - increase Pocket panel size to accomidate wider Russian text. */ +panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-viewstack > .panel-mainview:not([panelid="PanelUI-popup"]) { + max-width: 33em; /* standaloneSubviewWidth + 3 */ +} + +.cui-widget-panel[viewId="PanelUI-pocketView"] > .panel-arrowcontainer > .panel-arrowcontent { + padding-top: 0; + padding-bottom: 0; +} + +#PanelUI-pocketView > .panel-subview-body, +#PanelUI-pocketView { + overflow: visible; +} + +#pocket-button { + list-style-image: url("chrome://browser/skin/Toolbar.png"); +} + +toolbar[brighttext] #pocket-button { + list-style-image: url(chrome://browser/skin/Toolbar-inverted.png); +} + +@media not all and (min-resolution: 1.1dppx) { + #pocket-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #pocket-button { + list-style-image: var(--menupanel-list-style-image); + -moz-image-region: rect(0px, 992px, 32px, 960px); + } + + #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] { + -moz-image-region: rect(32px, 992px, 64px, 960px); + } +} + +@media (min-resolution: 1.1dppx) { + #pocket-button { + list-style-image: url("chrome://browser/skin/Toolbar@2x.png"); + } + + toolbar[brighttext] #pocket-button { + list-style-image: url("chrome://browser/skin/Toolbar-inverted@2x.png"); + } + + #pocket-button[cui-areatype="menu-panel"], + toolbarpaletteitem[place="palette"] > #pocket-button { + list-style-image: var(--menupanel-list-style-image-2x); + -moz-image-region: rect(0px, 1984px, 64px, 1920px); + } + + #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] { + -moz-image-region: rect(64px, 1984px, 128px, 1920px); + } +} + +#pocket-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 774px, 18px, 756px); +} + +#pocket-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(18px, 774px, 36px, 756px); +} + +#panelMenu_pocket, +#menu_pocket, +#BMB_pocket { + list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16.png"); +}
new file mode 100644 --- /dev/null +++ b/browser/extensions/pocket/skin/windows/pocket.css @@ -0,0 +1,9 @@ +@media (min-resolution: 1.1dppx) { + #pocket-button[cui-areatype="toolbar"] { + -moz-image-region: rect(0, 1548px, 36px, 1512px); + } + + #pocket-button[cui-areatype="toolbar"][open] { + -moz-image-region: rect(36px, 1548px, 72px, 1512px); + } +}
--- a/browser/locales/Makefile.in +++ b/browser/locales/Makefile.in @@ -128,16 +128,17 @@ libs:: $(call MERGE_FILES,$(addprefix pr libs-%: $(NSINSTALL) -D $(DIST)/install @$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)' @$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$* ifdef MOZ_WEBAPP_RUNTIME @$(MAKE) -C ../../webapprt/locales AB_CD=$* XPI_NAME=locale-$* endif @$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$* + @$(MAKE) -C ../extensions/pocket/locales AB_CD=$* XPI_NAME=locale-$* @$(MAKE) -C ../../intl/locales AB_CD=$* XPI_NAME=locale-$* @$(MAKE) -C ../../devtools/client/locales AB_CD=$* XPI_NAME=locale-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)' @$(MAKE) -B searchplugins AB_CD=$* XPI_NAME=locale-$* @$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR) @$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$* repackage-win32-installer: WIN32_INSTALLER_OUT=$(_ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe repackage-win32-installer: $(call ESCAPE_WILDCARD,$(WIN32_INSTALLER_IN)) $(SUBMAKEFILES) libs-$(AB_CD)
--- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -929,15 +929,8 @@ you can use these alternative items. Oth <!ENTITY panicButton.thankyou.buttonlabel "Thanks!"> <!ENTITY emeLearnMoreContextMenu.label "Learn more about DRM…"> <!ENTITY emeLearnMoreContextMenu.accesskey "D"> <!ENTITY emeNotificationsNotNow.label "Not now"> <!ENTITY emeNotificationsNotNow.accesskey "N"> <!ENTITY emeNotificationsDontAskAgain.label "Don't ask me again"> <!ENTITY emeNotificationsDontAskAgain.accesskey "D"> - -<!-- LOCALIZATION NOTE (saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): Pocket is a brand name --> -<!ENTITY saveToPocketCmd.label "Save Page to Pocket"> -<!ENTITY saveToPocketCmd.accesskey "k"> -<!ENTITY saveLinkToPocketCmd.label "Save Link to Pocket"> -<!ENTITY saveLinkToPocketCmd.accesskey "o"> -<!ENTITY pocketMenuitem.label "View Pocket List">
--- a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties +++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties @@ -119,15 +119,10 @@ web-apps-button.label = Apps web-apps-button.tooltiptext = Discover Apps # LOCALIZATION NOTE(devtools-webide-button.label, devtools-webide-button.tooltiptext): # widget is only visible after WebIDE has been started once (Tools > Web Developers > WebIDE) # %S is the keyboard shortcut devtools-webide-button2.label = WebIDE devtools-webide-button2.tooltiptext = Open WebIDE (%S) -# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext): "Pocket" -# is a brand name. -pocket-button.label = Pocket -pocket-button.tooltiptext = Save to Pocket - e10s-button.label = New Non-e10s Window e10s-button.tooltiptext = Open a new Non-e10s Window
--- a/browser/locales/filter.py +++ b/browser/locales/filter.py @@ -6,17 +6,18 @@ def test(mod, path, entity = None): import re # ignore anything but Firefox if mod not in ("netwerk", "dom", "toolkit", "security/manager", "devtools/client", "devtools/shared", "browser", "webapprt", "extensions/reporter", "extensions/spellcheck", "other-licenses/branding/firefox", "browser/branding/official", - "services/sync"): + "services/sync", + "browser/extensions/pocket"): return "ignore" if mod not in ("browser", "extensions/spellcheck"): # we only have exceptions for browser and extensions/spellcheck return "error" if not entity: # the only files to ignore are spell checkers and search if mod == "extensions/spellcheck": return "ignore"
--- a/browser/locales/jar.mn +++ b/browser/locales/jar.mn @@ -19,17 +19,16 @@ #endif locale/browser/aboutSessionRestore.dtd (%chrome/browser/aboutSessionRestore.dtd) locale/browser/aboutTabCrashed.dtd (%chrome/browser/aboutTabCrashed.dtd) locale/browser/syncCustomize.dtd (%chrome/browser/syncCustomize.dtd) locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd) locale/browser/browser.dtd (%chrome/browser/browser.dtd) locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd) locale/browser/browser.properties (%chrome/browser/browser.properties) - locale/browser/browser-pocket.properties (%chrome/browser/browser-pocket.properties) locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties) locale/browser/lightweightThemes.properties (%chrome/browser/lightweightThemes.properties) locale/browser/loop/loop.properties (%chrome/browser/loop/loop.properties) locale/browser/newTab.dtd (%chrome/browser/newTab.dtd) locale/browser/newTab.properties (%chrome/browser/newTab.properties) locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd) locale/browser/pageInfo.properties (%chrome/browser/pageInfo.properties) locale/browser/quitDialog.properties (%chrome/browser/quitDialog.properties)
--- a/browser/locales/l10n.ini +++ b/browser/locales/l10n.ini @@ -7,16 +7,17 @@ depth = ../.. all = browser/locales/all-locales [compare] dirs = browser extensions/reporter other-licenses/branding/firefox browser/branding/official devtools/client + browser/extensions/pocket [includes] # non-central apps might want to use %(topsrcdir)s here, or other vars # RFE: that needs to be supported by compare-locales, too, though toolkit = toolkit/locales/l10n.ini services_sync = services/sync/locales/l10n.ini webapprt = webapprt/locales/l10n.ini
--- a/browser/modules/ReaderParent.jsm +++ b/browser/modules/ReaderParent.jsm @@ -8,33 +8,30 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components; this.EXPORTED_SYMBOLS = [ "ReaderParent" ]; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils","resource://gre/modules/PlacesUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "UITour", "resource:///modules/UITour.jsm"); const gStringBundle = Services.strings.createBundle("chrome://global/locale/aboutReader.properties"); var ReaderParent = { _readerModeInfoPanelOpen: false, MESSAGES: [ "Reader:AddToList", - "Reader:AddToPocket", "Reader:ArticleGet", "Reader:FaviconRequest", "Reader:ListStatusRequest", - "Reader:PocketEnabledGet", "Reader:RemoveFromList", "Reader:Share", "Reader:SystemUIVisibility", "Reader:UpdateReaderButton", "Reader:SetIntPref", "Reader:SetCharPref", ], @@ -42,54 +39,29 @@ var ReaderParent = { let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); for (let msg of this.MESSAGES) { mm.addMessageListener(msg, this); } }, receiveMessage: function(message) { switch (message.name) { - case "Reader:AddToPocket": { - let doc = message.target.ownerDocument; - let pocketWidget = doc.getElementById("pocket-button"); - let placement = CustomizableUI.getPlacementOfWidget("pocket-button"); - if (placement) { - if (placement.area == CustomizableUI.AREA_PANEL) { - doc.defaultView.PanelUI.show().then(function() { - // The DOM node might not exist yet if the panel wasn't opened before. - pocketWidget = doc.getElementById("pocket-button"); - pocketWidget.doCommand(); - }); - } else { - pocketWidget.doCommand(); - } - } - break; - } - case "Reader:ArticleGet": this._getArticle(message.data.url, message.target).then((article) => { // Make sure the target browser is still alive before trying to send data back. if (message.target.messageManager) { message.target.messageManager.sendAsyncMessage("Reader:ArticleData", { article: article }); } }, e => { if (e && e.newURL) { message.target.loadURI("about:reader?url=" + encodeURIComponent(e.newURL)); } }); break; - case "Reader:PocketEnabledGet": { - let pocketPlacement = CustomizableUI.getPlacementOfWidget("pocket-button"); - let isPocketEnabled = pocketPlacement && pocketPlacement.area; - message.target.messageManager.sendAsyncMessage("Reader:PocketEnabledData", { enabled: !!isPocketEnabled}); - break; - } - case "Reader:FaviconRequest": { if (message.target.messageManager) { let faviconUrl = PlacesUtils.promiseFaviconLinkUrl(message.data.url); faviconUrl.then(function onResolution(favicon) { message.target.messageManager.sendAsyncMessage("Reader:FaviconReturn", { url: message.data.url, faviconUrl: favicon.path.replace(/^favicon:/, "") })
--- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -519,22 +519,16 @@ menuitem:not([type]):not(.menuitem-toolt list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png"); } #BMB_unsortedBookmarks, #panelMenu_unsortedBookmarks { list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png"); } -#panelMenu_pocket, -#menu_pocket, -#BMB_pocket { - list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png"); -} - #menu_openDownloads { list-style-image: url("chrome://browser/skin/Toolbar-small.png"); -moz-image-region: rect(0px 16px 16px 0px); } #menu_openAddons { list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); }
--- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -588,34 +588,16 @@ toolbarpaletteitem[place="palette"] > #p list-style-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png"); } #BMB_unsortedBookmarks { list-style-image: url("chrome://browser/skin/places/unfiledBookmarks@2x.png"); } } -#panelMenu_pocket, -#menu_pocket, -#BMB_pocket { - list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png"); -} - -@media (min-resolution: 2dppx) { - #panelMenu_pocket, - #menu_pocket, - #BMB_pocket { - list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16@2x.png"); - } - - #panelMenu_pocket > .toolbarbutton-icon { - width: 16px; - } -} - /* ----- PRIMARY TOOLBAR BUTTONS ----- */ :-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1 > .toolbarbutton-icon, :-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon { max-width: 16px; margin: 1px; } @@ -834,20 +816,16 @@ toolbar .toolbarbutton-1 > .toolbarbutto #e10s-button@toolbarButtonPressed@ { -moz-image-region: rect(18px, 342px, 36px, 324px); } #webide-button@toolbarButtonPressed@ { -moz-image-region: rect(18px, 738px, 36px, 720px); } - #pocket-button@toolbarButtonPressed@ { - -moz-image-region: rect(18px, 774px, 36px, 756px); - } - #new-tab-button@toolbarButtonPressed@ { -moz-image-region: rect(18px, 360px, 36px, 342px); } #privatebrowsing-button@toolbarButtonPressed@ { -moz-image-region: rect(18px, 378px, 36px, 360px); } @@ -1001,20 +979,16 @@ toolbar .toolbarbutton-1 > .toolbarbutto #e10s-button > .toolbarbutton-icon { transform: scaleY(-1); } #webide-button@toolbarButtonPressed@ { -moz-image-region: rect(36px, 1476px, 72px, 1440px); } - #pocket-button@toolbarButtonPressed@ { - -moz-image-region: rect(36px, 1548px, 72px, 1512px); - } - #new-tab-button@toolbarButtonPressed@ { -moz-image-region: rect(36px, 720px, 72px, 684px); } #privatebrowsing-button@toolbarButtonPressed@ { -moz-image-region: rect(36px, 756px, 72px, 720px); }
--- a/browser/themes/shared/browser.inc +++ b/browser/themes/shared/browser.inc @@ -1,13 +1,13 @@ %filter substitution % Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none. %define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button -%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #web-apps-button, #webide-button, #pocket-button +%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #web-apps-button, #webide-button %ifdef XP_MACOSX % Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen % and want it to behave like other toolbar buttons. %define primaryToolbarButtons @primaryToolbarButtons@, #restore-button %endif %define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css +++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css @@ -245,36 +245,26 @@ panelmultiview[nosubviews=true] > .panel max-width: @menuPanelWidth@; } #BMB_bookmarksPopup, .panel-mainview:not([panelid="PanelUI-popup"]) { max-width: @standaloneSubviewWidth@; } -/* Bug 1164419 - increase Pocket panel size to accomidate wider Russian text. */ -panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-viewstack > .panel-mainview:not([panelid="PanelUI-popup"]) { - max-width: 33em; /* standaloneSubviewWidth + 3 */ -} - panelview:not([mainview]) .toolbarbutton-text, .cui-widget-panel toolbarbutton > .toolbarbutton-text { text-align: start; display: -moz-box; } .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent { padding: 4px 0; } -.cui-widget-panel[viewId="PanelUI-pocketView"] > .panel-arrowcontainer > .panel-arrowcontent { - padding-top: 0; - padding-bottom: 0; -} - .cui-widget-panel.cui-widget-panelWithFooter > .panel-arrowcontainer > .panel-arrowcontent { padding-bottom: 0; } #PanelUI-contents { display: block; flex: 1 0 auto; margin-left: auto; @@ -1400,19 +1390,17 @@ toolbaritem[overflowedItem=true], menuitem[checked="true"].subviewbutton > .menu-iconic-left { visibility: hidden; } .panel-mainview[panelid=customizationui-widget-panel], #customizationui-widget-multiview > .panel-viewcontainer, #customizationui-widget-multiview > .panel-viewcontainer > .panel-viewstack, #PanelUI-panicView > .panel-subview-body, -#PanelUI-panicView, -#PanelUI-pocketView > .panel-subview-body, -#PanelUI-pocketView { +#PanelUI-panicView { overflow: visible; } #PanelUI-panicView.cui-widget-panelview { min-width: 280px; } #PanelUI-panic-timeframe {
--- a/browser/themes/shared/menupanel.inc.css +++ b/browser/themes/shared/menupanel.inc.css @@ -163,25 +163,16 @@ -moz-image-region: rect(0, 928px, 32px, 896px); } #webide-button[cui-areatype="menu-panel"], toolbarpaletteitem[place="palette"] > #webide-button { -moz-image-region: rect(0px, 960px, 32px, 928px); } - #pocket-button[cui-areatype="menu-panel"], - toolbarpaletteitem[place="palette"] > #pocket-button { - -moz-image-region: rect(0px, 992px, 32px, 960px); - } - - #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] { - -moz-image-region: rect(32px, 992px, 64px, 960px); - } - toolbaritem[sdkstylewidget="true"] > toolbarbutton { -moz-image-region: rect(0, 832px, 32px, 800px); } /* Wide panel control icons */ #edit-controls@inAnyPanel@ > toolbarbutton, #zoom-controls@inAnyPanel@ > toolbarbutton, @@ -310,25 +301,16 @@ -moz-image-region: rect(0px, 1024px, 64px, 960px); } #webide-button[cui-areatype="menu-panel"], toolbarpaletteitem[place="palette"] > #webide-button { -moz-image-region: rect(0px, 1920px, 64px, 1856px); } - #pocket-button[cui-areatype="menu-panel"], - toolbarpaletteitem[place="palette"] > #pocket-button { - -moz-image-region: rect(0px, 1984px, 64px, 1920px); - } - - #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] { - -moz-image-region: rect(64px, 1984px, 128px, 1920px); - } - #new-tab-button[cui-areatype="menu-panel"], toolbarpaletteitem[place="palette"] > #new-tab-button { -moz-image-region: rect(0px, 1088px, 64px, 1024px); } #privatebrowsing-button[cui-areatype="menu-panel"], toolbarpaletteitem[place="palette"] > #privatebrowsing-button { -moz-image-region: rect(0px, 1152px, 64px, 1088px);
--- a/browser/themes/shared/toolbarbuttons.inc.css +++ b/browser/themes/shared/toolbarbuttons.inc.css @@ -170,28 +170,16 @@ toolbar[brighttext] #bookmarks-menu-butt #web-apps-button[cui-areatype="toolbar"] { -moz-image-region: rect(0, 720px, 18px, 702px); } #webide-button[cui-areatype="toolbar"] { -moz-image-region: rect(0, 738px, 18px, 720px); } -#pocket-button[cui-areatype="toolbar"] { - -moz-image-region: rect(0, 774px, 18px, 756px); -} - -#pocket-button[cui-areatype="toolbar"][open] { -%ifdef XP_MACOSX - -moz-image-region: rect(36px, 774px, 54px, 756px); -%else - -moz-image-region: rect(18px, 774px, 36px, 756px); -%endif -} - %if defined(XP_WIN) || defined(XP_MACOSX) @media (min-resolution: 1.1dppx) { :-moz-any(@primaryToolbarButtons@), #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon { list-style-image: url("chrome://browser/skin/Toolbar@2x.png"); } toolbar[brighttext] :-moz-any(@primaryToolbarButtons@), @@ -352,22 +340,10 @@ toolbar[brighttext] #bookmarks-menu-butt #web-apps-button[cui-areatype="toolbar"] { -moz-image-region: rect(0, 1440px, 36px, 1404px); } #webide-button[cui-areatype="toolbar"] { -moz-image-region: rect(0, 1476px, 36px, 1440px); } - - #pocket-button[cui-areatype="toolbar"] { - -moz-image-region: rect(0, 1548px, 36px, 1512px); - } - - #pocket-button[cui-areatype="toolbar"][open] { -%ifdef XP_MACOSX - -moz-image-region: rect(72px, 1548px, 108px, 1512px); -%else - -moz-image-region: rect(36px, 1548px, 72px, 1512px); -%endif - } } %endif
--- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -2299,22 +2299,16 @@ notification[value="translation"] { } #BMB_unsortedBookmarks, #panelMenu_unsortedBookmarks { list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png"); -moz-image-region: auto; } -#panelMenu_pocket, -#menu_pocket, -#BMB_pocket { - list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png"); -} - /* ::::: Keyboard UI Panel ::::: */ .KUI-panel { -moz-appearance: none; background: rgba(27%,27%,27%,.9) url(KUI-background.png) repeat-x; color: white; border-style: none; border-radius: 20px;
--- a/devtools/.eslintrc +++ b/devtools/.eslintrc @@ -89,17 +89,17 @@ // Enforces spacing between keys and values in object literal properties. "key-spacing": [1, {"beforeColon": false, "afterColon": true}], // Allow mixed 'LF' and 'CRLF' as linebreaks. "linebreak-style": 0, // Don't enforce the maximum depth that blocks can be nested. The complexity // rule is a better rule to check this. "max-depth": 0, // Maximum length of a line. - "max-len": [1, 80], + "max-len": [1, 80, 2, {"ignoreUrls": true, "ignorePattern": "^\\s*loader\\.lazy"}], // Maximum depth callbacks can be nested. "max-nested-callbacks": [2, 3], // Don't limit the number of parameters that can be used in a function. "max-params": 0, // Don't limit the maximum number of statement allowed in a function. We // already have the complexity rule that's a better measurement. "max-statements": 0, // Require a capital letter for constructors, only check if all new
--- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -14,17 +14,17 @@ const OS_HISTOGRAM = "DEVTOOLS_OS_ENUMER const OS_IS_64_BITS = "DEVTOOLS_OS_IS_64_BITS_PER_USER"; const SCREENSIZE_HISTOGRAM = "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER"; var {Cc, Ci, Cu} = require("chrome"); var promise = require("promise"); var EventEmitter = require("devtools/shared/event-emitter"); var Telemetry = require("devtools/client/shared/telemetry"); var HUDService = require("devtools/client/webconsole/hudservice"); -var sourceUtils = require("devtools/client/shared/source-utils"); +var viewSource = require("devtools/client/shared/view-source"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://devtools/client/framework/gDevTools.jsm"); Cu.import("resource://devtools/client/scratchpad/scratchpad-manager.jsm"); Cu.import("resource://devtools/client/shared/DOMHelpers.jsm"); Cu.import("resource://gre/modules/Task.jsm"); loader.lazyImporter(this, "CommandUtils", @@ -2131,40 +2131,40 @@ Toolbox.prototype = { return this.frame.contentWindow.gViewSourceUtils; }, /** * Opens source in style editor. Falls back to plain "view-source:". * @see devtools/client/shared/source-utils.js */ viewSourceInStyleEditor: function(sourceURL, sourceLine) { - return sourceUtils.viewSourceInStyleEditor(this, sourceURL, sourceLine); + return viewSource.viewSourceInStyleEditor(this, sourceURL, sourceLine); }, /** * Opens source in debugger. Falls back to plain "view-source:". * @see devtools/client/shared/source-utils.js */ viewSourceInDebugger: function(sourceURL, sourceLine) { - return sourceUtils.viewSourceInDebugger(this, sourceURL, sourceLine); + return viewSource.viewSourceInDebugger(this, sourceURL, sourceLine); }, /** * Opens source in scratchpad. Falls back to plain "view-source:". * TODO The `sourceURL` for scratchpad instances are like `Scratchpad/1`. * If instances are scoped one-per-browser-window, then we should be able * to infer the URL from this toolbox, or use the built in scratchpad IN * the toolbox. * * @see devtools/client/shared/source-utils.js */ viewSourceInScratchpad: function(sourceURL, sourceLine) { - return sourceUtils.viewSourceInScratchpad(sourceURL, sourceLine); + return viewSource.viewSourceInScratchpad(sourceURL, sourceLine); }, /** * Opens source in plain "view-source:". * @see devtools/client/shared/source-utils.js */ viewSource: function(sourceURL, sourceLine) { - return sourceUtils.viewSource(this, sourceURL, sourceLine); + return viewSource.viewSource(this, sourceURL, sourceLine); }, };
--- a/devtools/client/memory/app.js +++ b/devtools/client/memory/app.js @@ -93,17 +93,17 @@ const App = createClass({ onClick: onClickSnapshotListItem, diffing, }), HeapView({ snapshot: selectedSnapshot, diffing, onSnapshotClick: () => dispatch(takeSnapshotAndCensus(front, heapWorker)), - toolbox + onViewSourceInDebugger: frame => toolbox.viewSourceInDebugger(frame.source, frame.line), }) ) ) ); }, }); /**
deleted file mode 100644 --- a/devtools/client/memory/components/frame.js +++ /dev/null @@ -1,40 +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/. */ - -const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react"); -const { L10N, parseSource } = require("../utils"); - -const Frame = module.exports = createClass({ - displayName: "frame-view", - - propTypes: { - frame: PropTypes.object.isRequired, - toolbox: PropTypes.object.isRequired, - }, - - render() { - let { toolbox, frame } = this.props; - const { short, long, host } = parseSource(frame.source); - - let func = frame.functionDisplayName || ""; - let tooltip = `${func} (${long}:${frame.line}:${frame.column})`; - let viewTooltip = L10N.getFormatStr("viewsourceindebugger", `${long}:${frame.line}:${frame.column}`); - let onClick = () => toolbox.viewSourceInDebugger(long, frame.line); - - let fields = [ - dom.span({ className: "frame-link-function-display-name" }, func), - dom.a({ className: "frame-link-filename", onClick, title: viewTooltip }, short), - dom.span({ className: "frame-link-colon" }, ":"), - dom.span({ className: "frame-link-line" }, frame.line), - dom.span({ className: "frame-link-colon" }, ":"), - dom.span({ className: "frame-link-column" }, frame.column) - ]; - - if (host) { - fields.push(dom.span({ className: "frame-link-host" }, host)); - } - - return dom.span({ className: "frame-link", title: tooltip }, ...fields); - } -});
--- a/devtools/client/memory/components/heap.js +++ b/devtools/client/memory/components/heap.js @@ -29,21 +29,21 @@ function createParentMap (node, aggregat return aggregator; } /** * Creates properties to be passed into the Tree component. * * @param {censusModel} census - * @param {Object} toolbox + * @param {Function} onViewSourceInDebugger * @param {Object} diffing * @return {Object} */ -function createTreeProperties(census, toolbox, diffing) { +function createTreeProperties(census, onViewSourceInDebugger, diffing) { const report = census.report; let map = createParentMap(report); const { totalBytes, totalCount } = report; const getPercentBytes = totalBytes === 0 ? _ => 0 : bytes => (bytes / totalBytes) * 100; @@ -55,17 +55,17 @@ function createTreeProperties(census, to autoExpandDepth: 0, getParent: node => { const parent = map[node.id]; return parent === report ? null : parent; }, getChildren: node => node.children || [], renderItem: (item, depth, focused, arrow, expanded) => new TreeItem({ - toolbox, + onViewSourceInDebugger, item, depth, focused, arrow, expanded, getPercentBytes, getPercentCount, showSign: !!diffing, @@ -86,22 +86,22 @@ function createTreeProperties(census, to */ const Heap = module.exports = createClass({ displayName: "heap-view", propTypes: { onSnapshotClick: PropTypes.func.isRequired, snapshot: snapshotModel, - toolbox: PropTypes.object.isRequired, + onViewSourceInDebugger: PropTypes.func.isRequired, diffing: diffingModel, }, render() { - let { snapshot, diffing, onSnapshotClick, toolbox } = this.props; + let { snapshot, diffing, onSnapshotClick, onViewSourceInDebugger } = this.props; let census; let state; let statusText; let error; if (diffing) { census = diffing.census; state = diffing.state; @@ -179,17 +179,17 @@ const Heap = module.exports = createClas content.push( dom.div({ className: "header" }, dom.span({ className: "heap-tree-item-bytes" }, L10N.getStr("heapview.field.bytes")), dom.span({ className: "heap-tree-item-count" }, L10N.getStr("heapview.field.count")), dom.span({ className: "heap-tree-item-total-bytes" }, L10N.getStr("heapview.field.totalbytes")), dom.span({ className: "heap-tree-item-total-count" }, L10N.getStr("heapview.field.totalcount")), dom.span({ className: "heap-tree-item-name" }, L10N.getStr("heapview.field.name")) ), - Tree(createTreeProperties(census, toolbox, diffing)) + Tree(createTreeProperties(census, onViewSourceInDebugger, diffing)) ); break; default: assert(false, "Unexpected state: ${state}"); } assert(!!content, "Should have set content in the above switch block");
--- a/devtools/client/memory/components/moz.build +++ b/devtools/client/memory/components/moz.build @@ -1,13 +1,12 @@ # 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/. DevToolsModules( - 'frame.js', 'heap.js', 'list.js', 'snapshot-list-item.js', 'toolbar.js', 'tree-item.js', )
--- a/devtools/client/memory/components/tree-item.js +++ b/devtools/client/memory/components/tree-item.js @@ -1,16 +1,17 @@ /* 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/. */ const { isSavedFrame } = require("devtools/shared/DevToolsUtils"); const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react"); const { L10N } = require("../utils"); -const FrameView = createFactory(require("./frame")); +const FrameView = createFactory(require("devtools/client/shared/components/frame")); +const unknownSourceString = L10N.getStr("unknownSource"); const INDENT = 10; const MAX_SOURCE_LENGTH = 200; /** * An arrow that displays whether its node is expanded (â–¼) or collapsed * (â–¶). When its node has no children, it is hidden. @@ -50,16 +51,17 @@ const TreeItem = module.exports = create item, depth, arrow, focused, toolbox, getPercentBytes, getPercentCount, showSign, + onViewSourceInDebugger, } = this.props; const bytes = this.formatNumber(showSign, item.bytes); const percentBytes = this.formatPercent(showSign, getPercentBytes(item.bytes)); const count = this.formatNumber(showSign, item.count); const percentCount = this.formatPercent(showSign, getPercentCount(item.count)); @@ -79,24 +81,31 @@ const TreeItem = module.exports = create dom.span({ className: "heap-tree-item-field heap-tree-item-total-bytes" }, dom.span({ className: "heap-tree-number" }, totalBytes), dom.span({ className: "heap-tree-percent" }, percentTotalBytes)), dom.span({ className: "heap-tree-item-field heap-tree-item-total-count" }, dom.span({ className: "heap-tree-number" }, totalCount), dom.span({ className: "heap-tree-percent" }, percentTotalCount)), dom.span({ className: "heap-tree-item-field heap-tree-item-name", style: { marginLeft: depth * INDENT }}, arrow, - this.toLabel(item.name, toolbox) + this.toLabel(item.name, onViewSourceInDebugger) ) ); }, - toLabel(name, toolbox) { + toLabel(name, linkToDebugger) { if (isSavedFrame(name)) { - return FrameView({ frame: name, toolbox }); + let onClickTooltipString = + L10N.getFormatStr("viewsourceindebugger",`${name.source}:${name.line}:${name.column}`); + return FrameView({ + frame: name, + onClick: () => linkToDebugger(name), + onClickTooltipString, + unknownSourceString + }); } if (name === null) { return L10N.getStr("tree-item.root"); } if (name === "noStack") { return L10N.getStr("tree-item.nostack");
--- a/devtools/client/memory/test/unit/test_utils.js +++ b/devtools/client/memory/test/unit/test_utils.js @@ -44,27 +44,8 @@ add_task(function *() { "utils.breakdownNameToSpec() works for presets"); let custom = { by: "internalType", then: { by: "count", bytes: true }}; Preferences.set("devtools.memory.custom-breakdowns", JSON.stringify({ "My Breakdown": custom })); ok(utils.breakdownEquals(utils.getCustomBreakdowns()["My Breakdown"], custom), "utils.getCustomBreakdowns() returns custom breakdowns"); }); - -// Test `utils.parseSource`. -add_task(function* () { - const url = "http://example.com/foo/bar/baz.js"; - let results = utils.parseSource(url); - equal(results.short, "baz.js"); - equal(results.long, url); - equal(results.host, "example.com"); - - results = utils.parseSource("self-hosted"); - equal(results.short, "self-hosted"); - equal(results.long, "self-hosted"); - equal(results.host, undefined); - - results = utils.parseSource(""); - equal(typeof results.short, "string"); - equal(typeof results.long, "string"); - equal(results.host, undefined); -});
--- a/devtools/client/memory/utils.js +++ b/devtools/client/memory/utils.js @@ -336,59 +336,16 @@ exports.getSnapshotTotals = function (ce bytes = report.totalBytes; count = report.totalCount; } return { bytes, count }; }; /** - * Parse a source into a short and long name as well as a host name. - * - * @param {String} source - * The source to parse. - * - * @returns {Object} - * An object with the following properties: - * - {String} short: A short name for the source. - * - {String} long: The full, long name for the source. - * - {String?} host: If available, the host name for the source. - */ -exports.parseSource = function (source) { - const sourceStr = source ? String(source) : ""; - - let short; - let long; - let host; - - try { - const url = new URL(sourceStr); - short = url.fileName; - host = url.host; - long = url.toString(); - } catch (e) { - // Malformed URI. - long = sourceStr; - short = sourceStr.slice(0, 100); - } - - if (!short) { - // Last ditch effort. - - if (!long) { - long = L10N.getStr("unknownSource"); - } - - short = long.slice(0, 100); - } - - return { short, long, host }; -}; - -/** * Takes some configurations and opens up a file picker and returns * a promise to the chosen file if successful. * * @param {String} .title * The title displayed in the file picker window. * @param {Array<Array<String>>} .filters * An array of filters to display in the file picker. Each filter in the array * is a duple of two strings, one a name for the filter, and one the filter itself
--- a/devtools/client/performance/modules/logic/frame-utils.js +++ b/devtools/client/performance/modules/logic/frame-utils.js @@ -1,50 +1,32 @@ /* 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 { Cc, Ci, Cu, Cr } = require("chrome"); - loader.lazyRequireGetter(this, "Services"); loader.lazyRequireGetter(this, "global", "devtools/client/performance/modules/global"); const demangle = require("devtools/client/shared/demangle"); +const { isChromeScheme, isContentScheme, parseURL } = + require("devtools/client/shared/source-utils"); // Character codes used in various parsing helper functions. -const CHAR_CODE_A = "a".charCodeAt(0); -const CHAR_CODE_C = "c".charCodeAt(0); -const CHAR_CODE_E = "e".charCodeAt(0); -const CHAR_CODE_F = "f".charCodeAt(0); -const CHAR_CODE_H = "h".charCodeAt(0); -const CHAR_CODE_I = "i".charCodeAt(0); -const CHAR_CODE_J = "j".charCodeAt(0); -const CHAR_CODE_L = "l".charCodeAt(0); -const CHAR_CODE_M = "m".charCodeAt(0); -const CHAR_CODE_O = "o".charCodeAt(0); -const CHAR_CODE_P = "p".charCodeAt(0); const CHAR_CODE_R = "r".charCodeAt(0); -const CHAR_CODE_S = "s".charCodeAt(0); -const CHAR_CODE_T = "t".charCodeAt(0); -const CHAR_CODE_U = "u".charCodeAt(0); const CHAR_CODE_0 = "0".charCodeAt(0); const CHAR_CODE_9 = "9".charCodeAt(0); const CHAR_CODE_CAP_Z = "Z".charCodeAt(0); const CHAR_CODE_LPAREN = "(".charCodeAt(0); const CHAR_CODE_RPAREN = ")".charCodeAt(0); const CHAR_CODE_COLON = ":".charCodeAt(0); -const CHAR_CODE_SLASH = "/".charCodeAt(0); const CHAR_CODE_SPACE = " ".charCodeAt(0); const CHAR_CODE_UNDERSCORE = "_".charCodeAt(0); -// The cache used in the `nsIURL` function. -const gNSURLStore = new Map(); - // The cache used to store inflated frames. const gInflatedFrameStore = new WeakMap(); // The cache used to store frame data from `getInfo`. const gFrameData = new WeakMap(); /** * Parses the raw location of this function call to retrieve the actual @@ -145,51 +127,41 @@ function parseLocation(location, fallbac i > 0 && location.charCodeAt(i - 1) === CHAR_CODE_SPACE) { parenIndex = i; break; } } } - let uri; + let parsedUrl; if (lineAndColumnIndex > 0) { let resource = location.substring(parenIndex + 1, lineAndColumnIndex); url = resource.split(" -> ").pop(); if (url) { - uri = nsIURL(url); + parsedUrl = parseURL(url); } } - let functionName, fileName, hostName, port, host; + let functionName, fileName, port, host; line = line || fallbackLine; column = column || fallbackColumn; - // If the URI digged out from the `location` is valid, this is a JS frame. - if (uri) { + // If the URL digged out from the `location` is valid, this is a JS frame. + if (parsedUrl) { functionName = location.substring(0, parenIndex - 1); - fileName = uri.fileName || "/"; - hostName = getHost(url, uri.host); - // nsIURL throws when accessing a piece of a URL that doesn't - // exist, because we can't have nice things. Only check this if hostName - // exists, to save an extra try/catch. - if (hostName) { - try { - port = uri.port === -1 ? null : uri.port; - host = port !== null ? `${hostName}:${port}` : hostName; - } catch (e) { - host = hostName; - } - } + fileName = parsedUrl.fileName; + port = parsedUrl.port; + host = parsedUrl.host; } else { functionName = location; url = null; } - return { functionName, fileName, hostName, host, port, url, line, column }; + return { functionName, fileName, host, port, url, line, column }; }; /** * Sets the properties of `isContent` and `category` on a frame. * * @param {InflatedFrame} frame */ function computeIsContentAndCategory(frame) { @@ -351,139 +323,16 @@ InflatedFrame.prototype.getFrameKey = fu options.isMetaCategoryOut = true; return this.category; } // Return an empty string denoting that this frame should be skipped. return ""; }; -/** - * Helper for getting an nsIURL instance out of a string. - */ -function nsIURL(url) { - let cached = gNSURLStore.get(url); - // If we cached a valid URI, or `null` in the case - // of a failure, return it. - if (cached !== void 0) { - return cached; - } - let uri = null; - try { - uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL); - // Access the host, because the constructor doesn't necessarily throw - // if it's invalid, but accessing the host can throw as well - uri.host; - } catch(e) { - // The passed url string is invalid. - uri = null; - } - - gNSURLStore.set(url, uri); - return uri; -}; - -/** - * Takes a `host` string from an nsIURL instance and - * returns the same string, or null, if it's an invalid host. - */ -function getHost (url, hostName) { - return isChromeScheme(url, 0) ? null : hostName; -} - -// For the functions below, we assume that we will never access the location -// argument out of bounds, which is indeed the vast majority of cases. -// -// They are written this way because they are hot. Each frame is checked for -// being content or chrome when processing the profile. - -function isColonSlashSlash(location, i) { - return location.charCodeAt(++i) === CHAR_CODE_COLON && - location.charCodeAt(++i) === CHAR_CODE_SLASH && - location.charCodeAt(++i) === CHAR_CODE_SLASH; -} - -function isContentScheme(location, i) { - let firstChar = location.charCodeAt(i); - - switch (firstChar) { - case CHAR_CODE_H: // "http://" or "https://" - if (location.charCodeAt(++i) === CHAR_CODE_T && - location.charCodeAt(++i) === CHAR_CODE_T && - location.charCodeAt(++i) === CHAR_CODE_P) { - if (location.charCodeAt(i + 1) === CHAR_CODE_S) { - ++i; - } - return isColonSlashSlash(location, i); - } - return false; - - case CHAR_CODE_F: // "file://" - if (location.charCodeAt(++i) === CHAR_CODE_I && - location.charCodeAt(++i) === CHAR_CODE_L && - location.charCodeAt(++i) === CHAR_CODE_E) { - return isColonSlashSlash(location, i); - } - return false; - - case CHAR_CODE_A: // "app://" - if (location.charCodeAt(++i) == CHAR_CODE_P && - location.charCodeAt(++i) == CHAR_CODE_P) { - return isColonSlashSlash(location, i); - } - return false; - - default: - return false; - } -} - -function isChromeScheme(location, i) { - let firstChar = location.charCodeAt(i); - - switch (firstChar) { - case CHAR_CODE_C: // "chrome://" - if (location.charCodeAt(++i) === CHAR_CODE_H && - location.charCodeAt(++i) === CHAR_CODE_R && - location.charCodeAt(++i) === CHAR_CODE_O && - location.charCodeAt(++i) === CHAR_CODE_M && - location.charCodeAt(++i) === CHAR_CODE_E) { - return isColonSlashSlash(location, i); - } - return false; - - case CHAR_CODE_R: // "resource://" - if (location.charCodeAt(++i) === CHAR_CODE_E && - location.charCodeAt(++i) === CHAR_CODE_S && - location.charCodeAt(++i) === CHAR_CODE_O && - location.charCodeAt(++i) === CHAR_CODE_U && - location.charCodeAt(++i) === CHAR_CODE_R && - location.charCodeAt(++i) === CHAR_CODE_C && - location.charCodeAt(++i) === CHAR_CODE_E) { - return isColonSlashSlash(location, i); - } - return false; - - case CHAR_CODE_J: // "jar:file://" - if (location.charCodeAt(++i) === CHAR_CODE_A && - location.charCodeAt(++i) === CHAR_CODE_R && - location.charCodeAt(++i) === CHAR_CODE_COLON && - location.charCodeAt(++i) === CHAR_CODE_F && - location.charCodeAt(++i) === CHAR_CODE_I && - location.charCodeAt(++i) === CHAR_CODE_L && - location.charCodeAt(++i) === CHAR_CODE_E) { - return isColonSlashSlash(location, i); - } - return false; - - default: - return false; - } -} - function isNumeric(c) { return c >= CHAR_CODE_0 && c <= CHAR_CODE_9; } function shouldDemangle(name) { return name && name.charCodeAt && name.charCodeAt(0) === CHAR_CODE_UNDERSCORE && name.charCodeAt(1) === CHAR_CODE_UNDERSCORE &&
--- a/devtools/client/performance/test/unit/test_frame-utils-01.js +++ b/devtools/client/performance/test/unit/test_frame-utils-01.js @@ -54,33 +54,33 @@ add_task(function () { for (let frame of CONTENT_LOCATIONS) { ok(isContent.apply(null, frameify(frame)), `${frame[0]} should be considered a content frame.`); } for (let frame of CHROME_LOCATIONS) { ok(!isContent.apply(null, frameify(frame)), `${frame[0]} should not be considered a content frame.`); } - // functionName, fileName, hostName, url, line, column - const FIELDS = ["functionName", "fileName", "hostName", "url", "line", "column", "host", "port"]; + // functionName, fileName, host, url, line, column + const FIELDS = ["functionName", "fileName", "host", "url", "line", "column", "host", "port"]; const PARSED_CONTENT = [ ["hello/<.world", "bar.js", "foo", "https://foo/bar.js", 123, 987, "foo", null], ["hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, 987, "foo", null], ["hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, null, "foo", null], ["hello/<.world", "bar.js", "foo", "http://foo/bar.js#baz", 123, 987, "foo", null], ["hello/<.world", "bar.js", "foo", "http://foo/bar.js?myquery=params&search=1", 123, 987, "foo", null], ["hello/<.world", "/", "foo", "http://foo/#bar", 123, 987, "foo", null], ["hello/<.world", "/", "foo", "http://foo/", 123, 987, "foo", null], ["hello/<.world", "file.js", "myfxosapp", "app://myfxosapp/file.js", 100, 1, "myfxosapp", null], - ["hello/<.world", "file.js", "localhost", "http://localhost:8888/file.js", 100, 1, "localhost:8888", 8888], - ["hello/<.world", "file.js", "localhost", "http://localhost:8888/file.js", 100, null, "localhost:8888", 8888], - ["hello/<.world", "/", "localhost", "http://localhost:8888/", 1, null, "localhost:8888", 8888], - ["hello/<.world", "/", "localhost", "http://localhost:8888/", 100, 50, "localhost:8888", 8888], - ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost", "http://localhost:8888/profiler.html", 4, null, "localhost:8888", 8888], - ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost", "http://localhost:8888/profiler.html", 4, 5, "localhost:8888", 8888], + ["hello/<.world", "file.js", "localhost:8888", "http://localhost:8888/file.js", 100, 1, "localhost:8888", 8888], + ["hello/<.world", "file.js", "localhost:8888", "http://localhost:8888/file.js", 100, null, "localhost:8888", 8888], + ["hello/<.world", "/", "localhost:8888", "http://localhost:8888/", 1, null, "localhost:8888", 8888], + ["hello/<.world", "/", "localhost:8888", "http://localhost:8888/", 100, 50, "localhost:8888", 8888], + ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost:8888", "http://localhost:8888/profiler.html", 4, null, "localhost:8888", 8888], + ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost:8888", "http://localhost:8888/profiler.html", 4, 5, "localhost:8888", 8888], ]; for (let i = 0; i < PARSED_CONTENT.length; i++) { let parsed = parseLocation.apply(null, CONTENT_LOCATIONS[i]); for (let j = 0; j < FIELDS.length; j++) { equal(parsed[FIELDS[j]], PARSED_CONTENT[i][j], `${CONTENT_LOCATIONS[i]} was parsed to correct ${FIELDS[j]}`); } }
--- a/devtools/client/performance/test/unit/test_tree-model-08.js +++ b/devtools/client/performance/test/unit/test_tree-model-08.js @@ -60,29 +60,29 @@ add_task(function test() { location: "main (http://localhost:8888/file.js:123:987)", line: 123, }), false), new FrameNode("main (resource://devtools/timeline.js:123)", compute({ location: "main (resource://devtools/timeline.js:123)", }), false), ]; - let fields = ["nodeType", "functionName", "fileName", "hostName", "url", "line", "column", "categoryData.abbrev", "isContent", "port"] + let fields = ["nodeType", "functionName", "fileName", "host", "url", "line", "column", "categoryData.abbrev", "isContent", "port"] let expected = [ - // nodeType, functionName, fileName, hostName, url, line, column, categoryData.abbrev, isContent, port + // nodeType, functionName, fileName, host, url, line, column, categoryData.abbrev, isContent, port ["Frame", "hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, 987, void 0, true], ["Frame", "hello/<.world", "bar.js", "foo", "http://foo/bar.js#baz", 123, 987, void 0, true], ["Frame", "hello/<.world", "/", "foo", "http://foo/#bar", 123, 987, void 0, true], ["Frame", "hello/<.world", "/", "foo", "http://foo/", 123, 987, void 0, true], ["Frame", "hello/<.world", "baz.js", "bar", "http://bar/baz.js", 123, 987, "other", false], ["Frame", "Foo::Bar::Baz", null, null, null, 456, void 0, "other", false], ["Frame", "EnterJIT", null, null, null, null, null, "js", false], ["Frame", "chrome://browser/content/content.js", null, null, null, 456, null, "other", false], ["Frame", "hello/<.world", "foo.js", null, "resource://gre/foo.js", 123, 434, "other", false], - ["Frame", "main", "file.js", "localhost", "http://localhost:8888/file.js", 123, 987, null, true, 8888], + ["Frame", "main", "file.js", "localhost:8888", "http://localhost:8888/file.js", 123, 987, null, true, 8888], ["Frame", "main", "timeline.js", null, "resource://devtools/timeline.js", 123, null, "tools", false] ]; for (let i = 0; i < frames.length; i++) { let info = frames[i].getInfo(); let expect = expected[i]; for (let j = 0; j < fields.length; j++) {
--- a/devtools/client/responsivedesign/responsivedesign.jsm +++ b/devtools/client/responsivedesign/responsivedesign.jsm @@ -47,16 +47,28 @@ this.ResponsiveUIManager = { * * @param aWindow the main window. * @param aTab the tab targeted. */ toggle: function(aWindow, aTab) { if (this.isActiveForTab(aTab)) { ActiveTabs.get(aTab).close(); } else { + this.runIfNeeded(aWindow, aTab); + } + }, + + /** + * Launches the responsive mode. + * + * @param aWindow the main window. + * @param aTab the tab targeted. + */ + runIfNeeded: function(aWindow, aTab) { + if (!this.isActiveForTab(aTab)) { new ResponsiveUI(aWindow, aTab); } }, /** * Returns true if responsive view is active for the provided tab. * * @param aTab the tab targeted. @@ -78,25 +90,21 @@ this.ResponsiveUIManager = { * @param aWindow the browser window. * @param aTab the tab targeted. * @param aCommand the command name. * @param aArgs command arguments. */ handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) { switch (aCommand) { case "resize to": - if (!this.isActiveForTab(aTab)) { - new ResponsiveUI(aWindow, aTab); - } + this.runIfNeeded(aWindow, aTab); ActiveTabs.get(aTab).setSize(aArgs.width, aArgs.height); break; case "resize on": - if (!this.isActiveForTab(aTab)) { - new ResponsiveUI(aWindow, aTab); - } + this.runIfNeeded(aWindow, aTab); break; case "resize off": if (this.isActiveForTab(aTab)) { ActiveTabs.get(aTab).close(); } break; case "resize toggle": this.toggle(aWindow, aTab); @@ -846,46 +854,48 @@ ResponsiveUI.prototype = { /** * Change the size of the browser. * * @param aWidth width of the browser. * @param aHeight height of the browser. */ setSize: function RUI_setSize(aWidth, aHeight) { - aWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH); - aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT); + this.setWidth(aWidth); + this.setHeight(aHeight); + }, - // We resize the containing stack. - let style = "max-width: %width;" + - "min-width: %width;" + - "max-height: %height;" + - "min-height: %height;"; + setWidth: function RUI_setWidth(aWidth) { + aWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH); + this.stack.style.maxWidth = this.stack.style.minWidth = aWidth + "px"; - style = style.replace(/%width/g, aWidth + "px"); - style = style.replace(/%height/g, aHeight + "px"); - - this.stack.setAttribute("style", style); - - if (!this.ignoreY) - this.resizeBarV.setAttribute("top", Math.round(aHeight / 2)); if (!this.ignoreX) this.resizeBarH.setAttribute("left", Math.round(aWidth / 2)); let selectedPreset = this.menuitems.get(this.selectedItem); - // We update the custom menuitem if we are using it if (selectedPreset.custom) { selectedPreset.width = aWidth; - selectedPreset.height = aHeight; - this.setMenuLabel(this.selectedItem, selectedPreset); } }, + setHeight: function RUI_setHeight(aHeight) { + aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT); + this.stack.style.maxHeight = this.stack.style.minHeight = aHeight + "px"; + + if (!this.ignoreY) + this.resizeBarV.setAttribute("top", Math.round(aHeight / 2)); + + let selectedPreset = this.menuitems.get(this.selectedItem); + if (selectedPreset.custom) { + selectedPreset.height = aHeight; + this.setMenuLabel(this.selectedItem, selectedPreset); + } + }, /** * Start the process of resizing the browser. * * @param aEvent */ startResizing: function RUI_startResizing(aEvent) { let selectedPreset = this.menuitems.get(this.selectedItem);
new file mode 100644 --- /dev/null +++ b/devtools/client/shared/components/frame.js @@ -0,0 +1,50 @@ +/* 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/. */ + +const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react"); +const { getSourceNames } = require("devtools/client/shared/source-utils"); + +const Frame = module.exports = createClass({ + displayName: "frame-view", + + propTypes: { + // SavedFrame + frame: PropTypes.object.isRequired, + // Clicking on the frame link -- probably should link to the debugger. + onClick: PropTypes.func.isRequired, + // Tooltip to display when hovering over the link to the frame; + // Something like "View source in debugger -> http://foo.com/file.js:100:2". + onClickTooltipString: PropTypes.string.isRequired, + // Source to display when cannot determine a good display name. + // Something like "(unknown)". + unknownSourceString: PropTypes.string.isRequired, + }, + + render() { + let { onClick, frame, onClickTooltipString, unknownSourceString } = this.props; + const { short, long, host } = getSourceNames(frame.source, unknownSourceString); + + let func = frame.functionDisplayName || ""; + let tooltip = `${func} (${long}:${frame.line}:${frame.column})`; + + let fields = [ + dom.span({ className: "frame-link-function-display-name" }, func), + dom.a({ + className: "frame-link-filename", + onClick, + title: onClickTooltipString + }, short), + dom.span({ className: "frame-link-colon" }, ":"), + dom.span({ className: "frame-link-line" }, frame.line), + dom.span({ className: "frame-link-colon" }, ":"), + dom.span({ className: "frame-link-column" }, frame.column) + ]; + + if (host) { + fields.push(dom.span({ className: "frame-link-host" }, host)); + } + + return dom.span({ className: "frame-link", title: tooltip }, ...fields); + } +});
--- a/devtools/client/shared/components/moz.build +++ b/devtools/client/shared/components/moz.build @@ -1,11 +1,12 @@ # -*- Mode: python; c-basic-offset: 4; 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/. DevToolsModules( + 'frame.js', 'tree.js', ) MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
--- a/devtools/client/shared/moz.build +++ b/devtools/client/shared/moz.build @@ -34,10 +34,11 @@ DevToolsModules( 'options-view.js', 'output-parser.js', 'poller.js', 'source-utils.js', 'SplitView.jsm', 'telemetry.js', 'theme-switching.js', 'theme.js', - 'undo.js' + 'undo.js', + 'view-source.js', )
--- a/devtools/client/shared/source-utils.js +++ b/devtools/client/shared/source-utils.js @@ -1,141 +1,210 @@ /* 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"; -loader.lazyRequireGetter(this, "Services"); -loader.lazyImporter(this, "gDevTools", "resource://devtools/client/framework/gDevTools.jsm"); -loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm"); +const { URL } = require("sdk/url"); -var DevToolsUtils = require("devtools/shared/DevToolsUtils"); +// Character codes used in various parsing helper functions. +const CHAR_CODE_A = "a".charCodeAt(0); +const CHAR_CODE_C = "c".charCodeAt(0); +const CHAR_CODE_E = "e".charCodeAt(0); +const CHAR_CODE_F = "f".charCodeAt(0); +const CHAR_CODE_H = "h".charCodeAt(0); +const CHAR_CODE_I = "i".charCodeAt(0); +const CHAR_CODE_J = "j".charCodeAt(0); +const CHAR_CODE_L = "l".charCodeAt(0); +const CHAR_CODE_M = "m".charCodeAt(0); +const CHAR_CODE_O = "o".charCodeAt(0); +const CHAR_CODE_P = "p".charCodeAt(0); +const CHAR_CODE_R = "r".charCodeAt(0); +const CHAR_CODE_S = "s".charCodeAt(0); +const CHAR_CODE_T = "t".charCodeAt(0); +const CHAR_CODE_U = "u".charCodeAt(0); +const CHAR_CODE_COLON = ":".charCodeAt(0); +const CHAR_CODE_SLASH = "/".charCodeAt(0); + +// The cache used in the `nsIURL` function. +const gURLStore = new Map(); /** - * Tries to open a Stylesheet file in the Style Editor. If the file is not found, - * it is opened in source view instead. - * Returns a promise resolving to a boolean indicating whether or not - * the source was able to be displayed in the StyleEditor, as the built-in Firefox - * View Source is the fallback. + * Takes a string and returns an object containing all the properties + * available on an URL instance, with additional properties (fileName), + * Leverages caching. + * + * @TODO If loaded through Browser Loader, we can use the web API URL + * directly, giving us the same interface without needing the SDK -- + * we still need to add `fileName` though. * - * @param {Toolbox} toolbox - * @param {string} sourceURL - * @param {number} sourceLine - * - * @return {Promise<boolean>} + * @param {String} location + * @return {Object?} An object containing most properties available + * in https://developer.mozilla.org/en-US/docs/Web/API/URL */ -exports.viewSourceInStyleEditor = Task.async(function *(toolbox, sourceURL, sourceLine) { - let panel = yield toolbox.loadTool("styleeditor"); + +function parseURL(location) { + let url = gURLStore.get(location); + + if (url !== void 0) { + return url; + } try { - yield panel.selectStyleSheet(sourceURL, sourceLine); - yield toolbox.selectTool("styleeditor"); - return true; - } catch (e) { - exports.viewSource(toolbox, sourceURL, sourceLine); - return false; + url = new URL(location); + // Definitions: + // Example: https://foo.com:8888/file.js + // `hostname`: "foo.com" + // `host`: "foo.com:8888" + // + // sdk/url does not match several definitions.: both `host` and `hostname` + // are actually the `hostname` (even though this is the `host` property on the + // original nsIURL, with `hostPort` representing the actual `host` name, AH!!!) + // So normalize all that garbage here. + let isChrome = isChromeScheme(location); + let fileName = url.fileName || "/"; + let hostname = isChrome ? null : url.hostname; + let host = isChrome ? null : + url.port ? `${url.host}:${url.port}` : + url.host; + + let parsed = Object.assign({}, url, { host, fileName, hostname }); + gURLStore.set(location, parsed); + return parsed; } -}); + catch (e) { + gURLStore.set(location, null); + return null; + } +} /** - * Tries to open a JavaScript file in the Debugger. If the file is not found, - * it is opened in source view instead. - * Returns a promise resolving to a boolean indicating whether or not - * the source was able to be displayed in the Debugger, as the built-in Firefox - * View Source is the fallback. - * - * @param {Toolbox} toolbox - * @param {string} sourceURL - * @param {number} sourceLine + * Parse a source into a short and long name as well as a host name. * - * @return {Promise<boolean>} + * @param {String} source + * The source to parse. Can be a URI or names like "(eval)" or "self-hosted". + * @param {String} unknownSourceString + * The string to use if no valid source name can be generated. + * @return {Object} + * An object with the following properties: + * - {String} short: A short name for the source. + * - {String} long: The full, long name for the source. + * - {String?} host: If available, the host name for the source. */ -exports.viewSourceInDebugger = Task.async(function *(toolbox, sourceURL, sourceLine) { - // If the Debugger was already open, switch to it and try to show the - // source immediately. Otherwise, initialize it and wait for the sources - // to be added first. - let debuggerAlreadyOpen = toolbox.getPanel("jsdebugger"); - let { panelWin: dbg } = yield toolbox.loadTool("jsdebugger"); +function getSourceNames (source, unknownSourceString) { + let short, long, host; + const sourceStr = source ? String(source) : ""; + const parsedUrl = parseURL(sourceStr); - if (!debuggerAlreadyOpen) { - yield dbg.DebuggerController.waitForSourcesLoaded(); + if (!parsedUrl) { + // Malformed URI. + long = sourceStr; + short = sourceStr.slice(0, 100); + } else { + short = parsedUrl.fileName; + long = parsedUrl.href; + host = parsedUrl.host; } - let { DebuggerView } = dbg; - let { Sources } = DebuggerView; - - let item = Sources.getItemForAttachment(a => a.source.url === sourceURL); - if (item) { - yield toolbox.selectTool("jsdebugger"); - const isLoading = dbg.DebuggerController.getState().sources.selectedSource !== item.attachment.source.actor; - DebuggerView.setEditorLocation(item.attachment.source.actor, sourceLine, { noDebug: true }); - if (isLoading) { - yield dbg.DebuggerController.waitForSourceShown(sourceURL); + if (!short) { + if (!long) { + long = unknownSourceString; } - return true; + short = long.slice(0, 100); } - // If not found, still attempt to open in View Source - exports.viewSource(toolbox, sourceURL, sourceLine); - return false; -}); + return { short, long, host }; +} + +// For the functions below, we assume that we will never access the location +// argument out of bounds, which is indeed the vast majority of cases. +// +// They are written this way because they are hot. Each frame is checked for +// being content or chrome when processing the profile. + +function isColonSlashSlash(location, i=0) { + return location.charCodeAt(++i) === CHAR_CODE_COLON && + location.charCodeAt(++i) === CHAR_CODE_SLASH && + location.charCodeAt(++i) === CHAR_CODE_SLASH; +} + +function isContentScheme(location, i=0) { + let firstChar = location.charCodeAt(i); -/** - * Tries to open a JavaScript file in the corresponding Scratchpad. - * - * @param {string} sourceURL - * @param {number} sourceLine - * - * @return {Promise} - */ -exports.viewSourceInScratchpad = Task.async(function *(sourceURL, sourceLine) { - // Check for matching top level scratchpad window. - let wins = Services.wm.getEnumerator("devtools:scratchpad"); + switch (firstChar) { + case CHAR_CODE_H: // "http://" or "https://" + if (location.charCodeAt(++i) === CHAR_CODE_T && + location.charCodeAt(++i) === CHAR_CODE_T &&