diff options
70 files changed, 604 insertions, 323 deletions
diff --git a/application/basilisk/components/nsBrowserGlue.js b/application/basilisk/components/nsBrowserGlue.js index 3258159b6..d77e97f87 100644 --- a/application/basilisk/components/nsBrowserGlue.js +++ b/application/basilisk/components/nsBrowserGlue.js @@ -1080,24 +1080,19 @@ BrowserGlue.prototype = { // For any add-ons that were installed disabled and can be enabled offer // them to the user. - let win = RecentWindow.getMostRecentBrowserWindow(); - AddonManager.getAllAddons(addons => { - for (let addon of addons) { - // If this add-on has already seen (or seen is undefined for non-XPI - // add-ons) then skip it. - if (addon.seen !== false) { - continue; - } - - // If this add-on cannot be enabled (either already enabled or - // appDisabled) then skip it. - if (!(addon.permissions & AddonManager.PERM_CAN_ENABLE)) { - continue; - } - - win.openUILinkIn("about:newaddon?id=" + addon.id, "tab"); - } - }); + let changedIDs = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED); + if (changedIDs.length > 0) { + let win = this.getMostRecentBrowserWindow(); + AddonManager.getAddonsByIDs(changedIDs, function(aAddons) { + aAddons.forEach(function(aAddon) { + // If the add-on isn't user disabled or can't be enabled then skip it. + if (!aAddon.userDisabled || !(aAddon.permissions & AddonManager.PERM_CAN_ENABLE)) + return; + + win.openUILinkIn("about:newaddon?id=" + aAddon.id, "tab"); + }) + }); + } let signingRequired; if (AppConstants.MOZ_REQUIRE_SIGNING) { @@ -1110,6 +1105,11 @@ BrowserGlue.prototype = { let disabledAddons = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED); AddonManager.getAddonsByIDs(disabledAddons, (addons) => { for (let addon of addons) { + // WEs return null, skip. + if (!addon) { + continue; + } + if (addon.type == "experiment") continue; diff --git a/application/basilisk/confvars.sh b/application/basilisk/confvars.sh index 62aa1a84f..cd18bdb94 100644 --- a/application/basilisk/confvars.sh +++ b/application/basilisk/confvars.sh @@ -55,7 +55,7 @@ MOZ_APP_STATIC_INI=1 MOZ_WEBGL_CONFORMANT=1 MOZ_JSDOWNLOADS=1 MOZ_WEBRTC=1 -MOZ_WEBEXTENSIONS=1 +MOZ_WEBEXTENSIONS= MOZ_DEVTOOLS=1 MOZ_SERVICES_COMMON=1 MOZ_SERVICES_SYNC=1 diff --git a/application/palemoon/components/downloads/content/downloads.js b/application/palemoon/components/downloads/content/downloads.js index ee728406c..ee1c6902e 100644 --- a/application/palemoon/components/downloads/content/downloads.js +++ b/application/palemoon/components/downloads/content/downloads.js @@ -1038,9 +1038,9 @@ const DownloadsView = { } // We must check for existence synchronously because this is a DOM event. - let file = new FileUtils.File(DownloadsView.controllerForElement(element) - .download.target.path); - if (!file.exists()) { + let localFile = new FileUtils.File(DownloadsView.controllerForElement(element) + .download.target.path); + if (!localFile.exists()) { return; } diff --git a/application/palemoon/components/nsBrowserGlue.js b/application/palemoon/components/nsBrowserGlue.js index f0a7aa22a..78b14a2e4 100644 --- a/application/palemoon/components/nsBrowserGlue.js +++ b/application/palemoon/components/nsBrowserGlue.js @@ -58,8 +58,8 @@ const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; // We try to backup bookmarks at idle times, to avoid doing that at shutdown. -// Number of idle seconds before trying to backup bookmarks. 15 minutes. -const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60; +// Number of idle seconds before trying to backup bookmarks. 10 minutes. +const BOOKMARKS_BACKUP_IDLE_TIME = 10 * 60; // Minimum interval in milliseconds between backups. const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000; // Maximum number of backups to create. Old ones will be purged. @@ -238,9 +238,9 @@ BrowserGlue.prototype = { this._onPlacesShutdown(); break; case "idle": - if ((this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) && - this._shouldBackupBookmarks()) + if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000) { this._backupBookmarks(); + } break; case "distribution-customization-complete": Services.obs.removeObserver(this, "distribution-customization-complete"); @@ -552,14 +552,6 @@ BrowserGlue.prototype = { this._showPlacesLockedNotificationBox(); } - // If there are plugins installed that are outdated, and the user hasn't - // been warned about them yet, open the plugins update page. - // Pale Moon: disable this functionality, people are already notified - // if they visit a page with an outdated plugin, and they can check - // properly from the plugins page as well. -// if (Services.prefs.getBoolPref(PREF_PLUGINS_NOTIFYUSER)) -// this._showPluginUpdatePage(); - // For any add-ons that were installed disabled and can be enabled offer // them to the user. let changedIDs = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED); @@ -949,8 +941,7 @@ BrowserGlue.prototype = { Services.prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks"); if (restoreDefaultBookmarks) { // Ensure that we already have a bookmarks backup for today. - if (this._shouldBackupBookmarks()) - yield this._backupBookmarks(); + yield this._backupBookmarks(); importBookmarks = true; } } catch(ex) {} @@ -959,7 +950,7 @@ BrowserGlue.prototype = { // from bookmarks.html, we will try to restore from JSON/JSONLZ4 if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) { // get latest JSON/JSONLZ4 backup - var bookmarksBackupFile = yield PlacesBackups.getMostRecentBackup(); + var bookmarksBackupFile = PlacesBackups.getMostRecentBackup(); if (bookmarksBackupFile) { // restore from JSON/JSONLZ4 backup yield BookmarkJSONUtils.importFromFile(bookmarksBackupFile, true); @@ -1102,75 +1093,60 @@ BrowserGlue.prototype = { } let waitingForBackupToComplete = true; - if (this._shouldBackupBookmarks()) { - waitingForBackupToComplete = false; - this._backupBookmarks().then( - function onSuccess() { - waitingForBackupToComplete = true; - }, - function onFailure() { - Cu.reportError("Unable to backup bookmarks."); - waitingForBackupToComplete = true; - } - ); - } + this._backupBookmarks().then( + function onSuccess() { + waitingForBackupToComplete = false; + }, + function onFailure() { + Cu.reportError("Unable to backup bookmarks."); + waitingForBackupToComplete = false; + } + ); // Backup bookmarks to bookmarks.html to support apps that depend // on the legacy format. - let waitingForHTMLExportToComplete = true; - // If this fails to get the preference value, we don't export. + let waitingForHTMLExportToComplete = false; if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) { - // Exceptionally, since this is a non-default setting and HTML format is - // discouraged in favor of the JSON/JSONLZ4 backups, we spin the event - // loop on shutdown, to wait for the export to finish. We cannot safely - // spin the event loop on shutdown until we include a watchdog to prevent - // potential hangs (bug 518683). The asynchronous shutdown operations - // will then be handled by a shutdown service (bug 435058). - waitingForHTMLExportToComplete = false; + // Exporting to HTML is explicitly enabled. + // We spin the event loop on shutdown, to wait for the export to finish. + waitingForHTMLExportToComplete = true; BookmarkHTMLUtils.exportToFile(BookmarkHTMLUtils.defaultPath).then( function onSuccess() { - waitingForHTMLExportToComplete = true; + waitingForHTMLExportToComplete = false; }, function onFailure() { Cu.reportError("Unable to auto export html."); - waitingForHTMLExportToComplete = true; + waitingForHTMLExportToComplete = false; } ); } + // The events loop should spin at least once because waitingForBackupToComplete + // is true before checking whether backup should be made. let thread = Services.tm.currentThread; - while (!waitingForBackupToComplete || !waitingForHTMLExportToComplete) { + while (waitingForBackupToComplete || waitingForHTMLExportToComplete) { thread.processNextEvent(true); } }, /** - * Determine whether to backup bookmarks or not. - * @return true if bookmarks should be backed up, false if not. - */ - _shouldBackupBookmarks: function BG__shouldBackupBookmarks() { - let lastBackupFile = PlacesBackups.getMostRecent(); - - // Should backup bookmarks if there are no backups or the maximum interval between - // backups elapsed. - return (!lastBackupFile || - new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL); - }, - - /** * Backup bookmarks. */ _backupBookmarks: function BG__backupBookmarks() { return Task.spawn(function() { - // Backup bookmarks if there are no backups or the maximum interval between - // backups elapsed. - let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS; - try { - maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups"); - } - catch(ex) { /* Use default. */ } + let lastBackupFile = yield PlacesBackups.getMostRecentBackup(); + // We should backup bookmarks if there are no backups or the maximum + // interval between backups has lapsed. + let hasLapsed = (new Date() - PlacesBackups.getDateForFile(lastBackupFile)) > BOOKMARKS_BACKUP_INTERVAL; + if (!lastBackupFile || hasLapsed) { + let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS; + try { + maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups"); + } + catch(ex) { /* Use default. */ } - yield PlacesBackups.create(maxBackups); // Don't force creation. + yield PlacesBackups.create(maxBackups); // Don't force creation. + } }); }, diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css index 516677fe6..b545b06cb 100644 --- a/application/palemoon/themes/linux/browser.css +++ b/application/palemoon/themes/linux/browser.css @@ -1781,9 +1781,9 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked"); } -#TabsToolbar[brighttext] .tab-icon-sound[soundplaying], -#TabsToolbar[brighttext] .tab-icon-sound[blocked], -#TabsToolbar[brighttext] .tab-icon-sound[muted] { +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[soundplaying], +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[blocked], +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[muted] { filter: invert(1); } @@ -1827,17 +1827,17 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked"); } -#TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), .tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white"); } -#TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), .tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted"); } -#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), .tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked"); } diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css index a7bd683bd..ddf050785 100644 --- a/application/palemoon/themes/osx/browser.css +++ b/application/palemoon/themes/osx/browser.css @@ -1844,9 +1844,9 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url- list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked"); } -#TabsToolbar[brighttext] .tab-icon-sound[soundplaying], -#TabsToolbar[brighttext] .tab-icon-sound[blocked], -#TabsToolbar[brighttext] .tab-icon-sound[muted] { +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[soundplaying], +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[blocked], +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[muted] { filter: invert(1); } @@ -1890,17 +1890,17 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url- list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked"); } -#TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), .tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white"); } -#TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), .tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted"); } -#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), .tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked"); } diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css index c261fe083..56a8318da 100644 --- a/application/palemoon/themes/windows/browser.css +++ b/application/palemoon/themes/windows/browser.css @@ -2050,9 +2050,9 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio.svg#tab-audio-blocked"); } -#TabsToolbar[brighttext] .tab-icon-sound[soundplaying], -#TabsToolbar[brighttext] .tab-icon-sound[blocked], -#TabsToolbar[brighttext] .tab-icon-sound[muted] { +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[soundplaying], +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[blocked], +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-sound[muted] { filter: invert(1); } @@ -2096,17 +2096,17 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action- list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked"); } -#TabsToolbar[brighttext] .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[soundplaying]:not([selected]):not(:hover), .tab-icon-overlay[soundplaying][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white"); } -#TabsToolbar[brighttext] .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[muted]:not([crashed]):not([selected]):not(:hover), .tab-icon-overlay[muted][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted"); } -#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), +#TabsToolbar:-moz-lwtheme-brighttext .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover), .tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked"); } diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp index ecea95dc1..75d408151 100644 --- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -297,6 +297,16 @@ nsNodeUtils::LastRelease(nsINode* aNode) NodeWillBeDestroyed, (aNode)); } + if (aNode->IsElement()) { + Element* elem = aNode->AsElement(); + FragmentOrElement::nsDOMSlots* domSlots = + static_cast<FragmentOrElement::nsDOMSlots*>(slots); + for (auto iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) { + DOMIntersectionObserver* observer = iter.Key(); + observer->UnlinkTarget(*elem); + } + } + delete slots; aNode->mSlots = nullptr; } diff --git a/dom/webidl/IntersectionObserver.webidl b/dom/webidl/IntersectionObserver.webidl index bc193ee8c..83200d950 100644 --- a/dom/webidl/IntersectionObserver.webidl +++ b/dom/webidl/IntersectionObserver.webidl @@ -7,7 +7,7 @@ * https://wicg.github.io/IntersectionObserver/ */ -[ProbablyShortLivingObject, Pref="dom.IntersectionObserver.enabled"] +[ProbablyShortLivingObject, Pref="dom.intersectionObserver.enabled"] interface IntersectionObserverEntry { [Constant] readonly attribute DOMHighResTimeStamp time; @@ -27,7 +27,7 @@ interface IntersectionObserverEntry { [Constructor(IntersectionCallback intersectionCallback, optional IntersectionObserverInit options), - Pref="dom.IntersectionObserver.enabled"] + Pref="dom.intersectionObserver.enabled"] interface IntersectionObserver { [Constant] readonly attribute Element? root; diff --git a/image/IDecodingTask.cpp b/image/IDecodingTask.cpp index a067e7a7d..6e2f039be 100644 --- a/image/IDecodingTask.cpp +++ b/image/IDecodingTask.cpp @@ -142,8 +142,10 @@ MetadataDecodingTask::Run() // AnonymousDecodingTask implementation. /////////////////////////////////////////////////////////////////////////////// -AnonymousDecodingTask::AnonymousDecodingTask(NotNull<Decoder*> aDecoder) +AnonymousDecodingTask::AnonymousDecodingTask(NotNull<Decoder*> aDecoder, + bool aResumable) : mDecoder(aDecoder) + , mResumable(aResumable) { } void @@ -168,5 +170,16 @@ AnonymousDecodingTask::Run() } } +void +AnonymousDecodingTask::Resume() +{ + // Anonymous decoders normally get all their data at once. We have some situations + // where they don't. If explicitly requested, resuming should be supported. + if (mResumable) { + RefPtr<AnonymousDecodingTask> self(this); + NS_DispatchToMainThread(NS_NewRunnableFunction([self]() -> void { self->Run(); })); + } +} + } // namespace image } // namespace mozilla diff --git a/image/IDecodingTask.h b/image/IDecodingTask.h index 196ce5fdc..3cbab5006 100644 --- a/image/IDecodingTask.h +++ b/image/IDecodingTask.h @@ -102,22 +102,20 @@ class AnonymousDecodingTask final : public IDecodingTask public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousDecodingTask, override) - explicit AnonymousDecodingTask(NotNull<Decoder*> aDecoder); + explicit AnonymousDecodingTask(NotNull<Decoder*> aDecoder, bool aResumable); void Run() override; bool ShouldPreferSyncRun() const override { return true; } TaskPriority Priority() const override { return TaskPriority::eLow; } - // Anonymous decoders normally get all their data at once. We have tests where - // they don't; in these situations, the test re-runs them manually. So no - // matter what, we don't want to resume by posting a task to the DecodePool. - void Resume() override { } + void Resume() override; private: virtual ~AnonymousDecodingTask() { } NotNull<RefPtr<Decoder>> mDecoder; + bool mResumable; }; } // namespace image diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp index addee7f15..ddd2f200e 100644 --- a/image/ImageOps.cpp +++ b/image/ImageOps.cpp @@ -126,7 +126,7 @@ ImageOps::DecodeToSurface(nsIInputStream* aInputStream, } // Run the decoder synchronously. - RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder)); + RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false); task->Run(); if (!decoder->GetDecodeDone() || decoder->HasError()) { return nullptr; diff --git a/image/SourceBuffer.cpp b/image/SourceBuffer.cpp index de0719d45..de066e29f 100644 --- a/image/SourceBuffer.cpp +++ b/image/SourceBuffer.cpp @@ -451,10 +451,18 @@ SourceBuffer::AppendFromInputStream(nsIInputStream* aInputStream, uint32_t bytesRead; nsresult rv = aInputStream->ReadSegments(AppendToSourceBuffer, this, aCount, &bytesRead); - if (!NS_WARN_IF(NS_FAILED(rv))) { - MOZ_ASSERT(bytesRead == aCount, - "AppendToSourceBuffer should consume everything"); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (bytesRead == 0) { + // The loading of the image has been canceled. + return NS_ERROR_FAILURE; } + + MOZ_ASSERT(bytesRead == aCount, + "AppendToSourceBuffer should consume everything"); + return rv; } diff --git a/image/SourceBuffer.h b/image/SourceBuffer.h index 64727e65e..6f2c74d33 100644 --- a/image/SourceBuffer.h +++ b/image/SourceBuffer.h @@ -174,6 +174,13 @@ public: return mState == READY ? mData.mIterating.mNextReadLength : 0; } + /// If we're ready to read, returns whether or not everything available thus + /// far has been in the same contiguous buffer. + bool IsContiguous() const { + MOZ_ASSERT(mState == READY, "Calling IsContiguous() in the wrong state"); + return mState == READY ? mData.mIterating.mChunk == 0 : false; + } + /// @return a count of the chunks we've advanced through. uint32_t ChunkCount() const { return mChunkCount; } diff --git a/image/decoders/nsWebPDecoder.cpp b/image/decoders/nsWebPDecoder.cpp index 4f3cc8b2a..3181e3a3a 100644 --- a/image/decoders/nsWebPDecoder.cpp +++ b/image/decoders/nsWebPDecoder.cpp @@ -144,6 +144,10 @@ nsWebPDecoder::UpdateBuffer(SourceBufferIterator& aIterator, switch (aState) { case SourceBufferIterator::READY: + if(!aIterator.IsContiguous()) { + //We need to buffer. This should be rare, but expensive. + break; + } if (!mData) { // For as long as we hold onto an iterator, we know the data pointers // to the chunks cannot change underneath us, so save the pointer to diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 0983f034f..799396a0a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6566,7 +6566,7 @@ struct JS_PUBLIC_API(PerformanceGroup) { uint64_t refCount_; }; -using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 0, SystemAllocPolicy>; +using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 8, SystemAllocPolicy>; /** * Commit any Performance Monitoring data. diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 7a6acb970..5b5ec6196 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -20,6 +20,7 @@ #include "gc/Zone.h" #include "vm/Runtime.h" + namespace js { bool @@ -136,6 +137,9 @@ PerformanceMonitoring::start() bool PerformanceMonitoring::commit() { + // Maximal initialization size, in elements for the vector of groups. + static const size_t MAX_GROUPS_INIT_CAPACITY = 1024; + #if !defined(MOZ_HAVE_RDTSC) // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`. return false; @@ -152,13 +156,24 @@ PerformanceMonitoring::commit() return true; } - PerformanceGroupVector recentGroups; - recentGroups_.swap(recentGroups); + // The move operation is generally constant time, unless + // `recentGroups_.length()` is very small, in which case + // it's fast just because it's small. + PerformanceGroupVector recentGroups(Move(recentGroups_)); + recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`. bool success = true; if (stopwatchCommitCallback) success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + // Heuristic: we expect to have roughly the same number of groups as in + // the previous iteration. + const size_t capacity = recentGroups.capacity() < MAX_GROUPS_INIT_CAPACITY ? + recentGroups.capacity() : + MAX_GROUPS_INIT_CAPACITY; + success = recentGroups_.reserve(capacity) + && success; + // Reset immediately, to make sure that we're not hit by the end // of a nested event loop (which would cause `commit` to be called // twice in succession). @@ -227,7 +242,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM MOZ_GUARD_OBJECT_NOTIFIER_INIT; JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); @@ -266,11 +281,11 @@ AutoStopwatch::~AutoStopwatch() } JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); - if (iteration_ != runtime->performanceMonitoring.iteration()) { + if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) { // We have entered a nested event loop at some point. // Any information we may have is obsolete. return; diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp index 37bb2b7a5..f1c797c9a 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleIterator.cpp @@ -321,7 +321,18 @@ status_t SampleIterator::findSampleTime( *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex); - *time += mTable->getCompositionTimeOffset(sampleIndex); + int32_t offset = mTable->getCompositionTimeOffset(sampleIndex); + if ((offset < 0 && *time < (offset == INT32_MIN ? + INT32_MAX : uint32_t(-offset))) || + (offset > 0 && *time > UINT32_MAX - offset)) { + ALOGE("%u + %d would overflow", *time, offset); + return ERROR_OUT_OF_RANGE; + } + if (offset > 0) { + *time += offset; + } else { + *time -= (offset == INT32_MIN ? INT32_MAX : (-offset)); + } return OK; } diff --git a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp index bbb2227e7..bc991e8e1 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/SampleTable.cpp @@ -52,14 +52,14 @@ struct SampleTable::CompositionDeltaLookup { CompositionDeltaLookup(); void setEntries( - const uint32_t *deltaEntries, size_t numDeltaEntries); + const int32_t *deltaEntries, size_t numDeltaEntries); - uint32_t getCompositionTimeOffset(uint32_t sampleIndex); + int32_t getCompositionTimeOffset(uint32_t sampleIndex); private: Mutex mLock; - const uint32_t *mDeltaEntries; + const int32_t *mDeltaEntries; size_t mNumDeltaEntries; size_t mCurrentDeltaEntry; @@ -76,7 +76,7 @@ SampleTable::CompositionDeltaLookup::CompositionDeltaLookup() } void SampleTable::CompositionDeltaLookup::setEntries( - const uint32_t *deltaEntries, size_t numDeltaEntries) { + const int32_t *deltaEntries, size_t numDeltaEntries) { Mutex::Autolock autolock(mLock); mDeltaEntries = deltaEntries; @@ -85,7 +85,7 @@ void SampleTable::CompositionDeltaLookup::setEntries( mCurrentEntrySampleIndex = 0; } -uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset( +int32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset( uint32_t sampleIndex) { Mutex::Autolock autolock(mLock); @@ -381,6 +381,10 @@ status_t SampleTable::setTimeToSampleParams( return OK; } +// NOTE: per 14996-12, version 0 ctts contains unsigned values, while version 1 +// contains signed values, however some software creates version 0 files that +// contain signed values, so we're always treating the values as signed, +// regardless of version. status_t SampleTable::setCompositionTimeToSampleParams( off64_t data_offset, size_t data_size) { ALOGV("There are reordered frames present."); @@ -398,8 +402,12 @@ status_t SampleTable::setCompositionTimeToSampleParams( uint32_t numEntries = U32_AT(&header[4]); - if (U32_AT(header) != 0 && numEntries) { - // Expected version = 0, flags = 0. + uint32_t flags = U32_AT(header); + uint32_t version = flags >> 24; + flags &= 0xffffff; + + if ((version != 0 && version != 1) || flags != 0) { + // Expected version = 0 or 1, flags = 0. return ERROR_MALFORMED; } @@ -408,7 +416,7 @@ status_t SampleTable::setCompositionTimeToSampleParams( } mNumCompositionTimeDeltaEntries = numEntries; - mCompositionTimeDeltaEntries = new (mozilla::fallible) uint32_t[2 * numEntries]; + mCompositionTimeDeltaEntries = new (mozilla::fallible) int32_t[2 * numEntries]; if (!mCompositionTimeDeltaEntries) { return ERROR_BUFFER_TOO_SMALL; } @@ -801,12 +809,28 @@ status_t SampleTable::buildSampleEntriesTable() { mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; - uint32_t compTimeDelta = + int32_t compTimeDelta = mCompositionDeltaLookup->getCompositionTimeOffset( sampleIndex); + if ((compTimeDelta < 0 && sampleTime < + (compTimeDelta == INT32_MIN ? + INT32_MAX : uint32_t(-compTimeDelta))) + || (compTimeDelta > 0 && + sampleTime > UINT32_MAX - compTimeDelta)) { + ALOGE("%u + %d would overflow, clamping", + sampleTime, compTimeDelta); + if (compTimeDelta < 0) { + sampleTime = 0; + } else { + sampleTime = UINT32_MAX; + } + compTimeDelta = 0; + } + mSampleTimeEntries[sampleIndex].mCompositionTime = - sampleTime + compTimeDelta; + compTimeDelta > 0 ? sampleTime + compTimeDelta: + sampleTime - (-compTimeDelta); } ++sampleIndex; @@ -1136,7 +1160,7 @@ status_t SampleTable::getMetaDataForSample( return OK; } -uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { +int32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex); } diff --git a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h index e115c92bb..c235f281e 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/frameworks/av/media/libstagefright/include/SampleTable.h @@ -134,7 +134,7 @@ private: }; SampleTimeEntry *mSampleTimeEntries; - uint32_t *mCompositionTimeDeltaEntries; + int32_t *mCompositionTimeDeltaEntries; size_t mNumCompositionTimeDeltaEntries; CompositionDeltaLookup *mCompositionDeltaLookup; @@ -171,7 +171,7 @@ private: friend struct SampleIterator; status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size); - uint32_t getCompositionTimeOffset(uint32_t sampleIndex); + int32_t getCompositionTimeOffset(uint32_t sampleIndex); static int CompareIncreasingTime(const void *, const void *); diff --git a/media/libwebp/AUTHORS b/media/libwebp/AUTHORS index 83c7b9c5e..0d70b7fb2 100644 --- a/media/libwebp/AUTHORS +++ b/media/libwebp/AUTHORS @@ -1,4 +1,5 @@ Contributors: +- Alan Browning (browning at google dot com) - Charles Munger (clm at google dot com) - Christian Duvivier (cduvivier at google dot com) - Djordje Pesut (djordje dot pesut at imgtec dot com) @@ -6,9 +7,10 @@ Contributors: - James Zern (jzern at google dot com) - Jan Engelhardt (jengelh at medozas dot de) - Jehan (jehan at girinstud dot io) -- Johann (johann dot koenig at duck dot com) +- Johann Koenig (johann dot koenig at duck dot com) - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) - Jyrki Alakuijala (jyrki at google dot com) +- Konstantin Ivlev (tomskside at gmail dot com) - Lode Vandevenne (lode at google dot com) - Lou Quillio (louquillio at google dot com) - Mans Rullgard (mans at mansr dot com) @@ -37,3 +39,4 @@ Contributors: - Vincent Rabaud (vrabaud at google dot com) - Vlad Tsyrklevich (vtsyrklevich at chromium dot org) - Yang Zhang (yang dot zhang at arm dot com) +- Yannis Guyon (yguyon at google dot com) diff --git a/media/libwebp/NEWS b/media/libwebp/NEWS index 480cb7d34..aa393c819 100644 --- a/media/libwebp/NEWS +++ b/media/libwebp/NEWS @@ -1,3 +1,23 @@ +- 1/14/2019: version 1.0.2 + This is a binary compatible release. + * (Windows) unicode file support in the tools (linux and mac already had + support, issue #398) + * lossless encoder speedups + * lossy encoder speedup on ARM + * lossless multi-threaded security fix (chromium:917029) + +- 11/2/2018: version 1.0.1 + This is a binary compatible release. + * lossless encoder speedups + * big-endian fix for alpha decoding (issue #393) + * gif2webp fix for loop count=65535 transcode (issue #382) + * further security related hardening in libwebp & libwebpmux + (issues #383, #385, #386, #387, #388, #391) + (oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170, + #9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349, + #10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152) + * miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400) + - 4/2/2018: version 1.0.0 This is a binary compatible release. * lossy encoder improvements to avoid chroma shifts in various circumstances diff --git a/media/libwebp/README b/media/libwebp/README index a76b3787f..502a4c1c2 100644 --- a/media/libwebp/README +++ b/media/libwebp/README @@ -4,7 +4,7 @@ \__\__/\____/\_____/__/ ____ ___ / _/ / \ \ / _ \/ _/ / \_/ / / \ \ __/ \__ - \____/____/\_____/_____/____/v1.0.0 + \____/____/\_____/_____/____/v1.0.2 Description: ============ @@ -136,6 +136,8 @@ cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../ or through your favorite interface (like ccmake or cmake-qt-gui). +Use option -DWEBP_UNICODE=ON for Unicode support on Windows (with chcp 65001). + Finally, once installed, you can also use WebP in your CMake project by doing: find_package(WebP) @@ -402,12 +404,14 @@ Options are: -nofilter .... disable in-loop filtering -dither <int> dithering strength (0..100), default=50 -noalphadither disable alpha plane dithering + -usebgcolor .. display background color -mt .......... use multi-threading -info ........ print info -h ........... this help message Keyboard shortcuts: 'c' ................ toggle use of color profile + 'b' ................ toggle background color display 'i' ................ overlay file information 'd' ................ disable blending & disposal (debug) 'q' / 'Q' / ESC .... quit @@ -470,6 +474,9 @@ Per-frame options (only used for subsequent images input): example: img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp +Note: if a single file name is passed as the argument, the arguments will be +tokenized from this file. The file name must not start with the character '-'. + Animated GIF conversion: ======================== Animated GIF files can be converted to WebP files with animation using the diff --git a/media/libwebp/README.mux b/media/libwebp/README.mux index bd4f92fa3..7e9c3c903 100644 --- a/media/libwebp/README.mux +++ b/media/libwebp/README.mux @@ -1,7 +1,7 @@  __ __ ____ ____ ____ __ __ _ __ __ / \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\ \ / __/ _ \ __/ / / (_/ /__ - \__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.0 + \__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.2 Description: @@ -211,6 +211,35 @@ Code example: For a detailed AnimEncoder API reference, please refer to the header file (src/webp/mux.h). +AnimDecoder API: +================ +This AnimDecoder API allows decoding (possibly) animated WebP images. + +Code Example: + + WebPAnimDecoderOptions dec_options; + WebPAnimDecoderOptionsInit(&dec_options); + // Tune 'dec_options' as needed. + WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options); + WebPAnimInfo anim_info; + WebPAnimDecoderGetInfo(dec, &anim_info); + for (uint32_t i = 0; i < anim_info.loop_count; ++i) { + while (WebPAnimDecoderHasMoreFrames(dec)) { + uint8_t* buf; + int timestamp; + WebPAnimDecoderGetNext(dec, &buf, ×tamp); + // ... (Render 'buf' based on 'timestamp'). + // ... (Do NOT free 'buf', as it is owned by 'dec'). + } + WebPAnimDecoderReset(dec); + } + const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec); + // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data). + WebPAnimDecoderDelete(dec); + +For a detailed AnimDecoder API reference, please refer to the header file +(src/webp/demux.h). + Bugs: ===== diff --git a/media/libwebp/UXPCHANGES b/media/libwebp/UXPCHANGES index 8c3eb5ad2..78b7823c8 100644 --- a/media/libwebp/UXPCHANGES +++ b/media/libwebp/UXPCHANGES @@ -2,3 +2,4 @@ Changes made to pristine libwebp source by Moonchild Productions and mozilla.org 2017/01/27 -- Synced with libwebp-0.6.0 (BZ #1294490). 2018/06/29 -- Synced with libwebp-1.0.0 + BUG=webp:381,383,384. +2019/01/21 -- Synced with libwebp-1.0.2 diff --git a/media/libwebp/dec/alphai_dec.h b/media/libwebp/dec/alphai_dec.h index 3b40691b5..d2a404dc5 100644 --- a/media/libwebp/dec/alphai_dec.h +++ b/media/libwebp/dec/alphai_dec.h @@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec); } // extern "C" #endif -#endif /* WEBP_DEC_ALPHAI_DEC_H_ */ +#endif // WEBP_DEC_ALPHAI_DEC_H_ diff --git a/media/libwebp/dec/common_dec.h b/media/libwebp/dec/common_dec.h index 9995f1a51..b158550a8 100644 --- a/media/libwebp/dec/common_dec.h +++ b/media/libwebp/dec/common_dec.h @@ -51,4 +51,4 @@ enum { MB_FEATURE_TREE_PROBS = 3, NUM_PROBAS = 11 }; -#endif // WEBP_DEC_COMMON_DEC_H_ +#endif // WEBP_DEC_COMMON_DEC_H_ diff --git a/media/libwebp/dec/frame_dec.c b/media/libwebp/dec/frame_dec.c index 57e4d9669..3d1d66274 100644 --- a/media/libwebp/dec/frame_dec.c +++ b/media/libwebp/dec/frame_dec.c @@ -338,7 +338,6 @@ void VP8InitDithering(const WebPDecoderOptions* const options, for (s = 0; s < NUM_MB_SEGMENTS; ++s) { VP8QuantMatrix* const dqm = &dec->dqm_[s]; if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) { - // TODO(skal): should we specially dither more for uv_quant_ < 0? const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_; dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3; } @@ -669,15 +668,9 @@ int VP8GetThreadMethod(const WebPDecoderOptions* const options, (void)height; assert(headers == NULL || !headers->is_lossless); #if defined(WEBP_USE_THREAD) - if (width < MIN_WIDTH_FOR_THREADS) return 0; - // TODO(skal): tune the heuristic further -#if 0 - if (height < 2 * width) return 2; + if (width >= MIN_WIDTH_FOR_THREADS) return 2; #endif - return 2; -#else // !WEBP_USE_THREAD return 0; -#endif } #undef MT_CACHE_LINES diff --git a/media/libwebp/dec/idec_dec.c b/media/libwebp/dec/idec_dec.c index c9506bc83..ee0d33eac 100644 --- a/media/libwebp/dec/idec_dec.c +++ b/media/libwebp/dec/idec_dec.c @@ -140,10 +140,9 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { if (NeedCompressedAlpha(idec)) { ALPHDecoder* const alph_dec = dec->alph_dec_; dec->alpha_data_ += offset; - if (alph_dec != NULL) { + if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) { if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; - assert(alph_vp8l_dec != NULL); assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, dec->alpha_data_ + ALPHA_HEADER_LEN, @@ -449,7 +448,10 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { VP8Decoder* const dec = (VP8Decoder*)idec->dec_; VP8Io* const io = &idec->io_; - assert(dec->ready_); + // Make sure partition #0 has been read before, to set dec to ready_. + if (!dec->ready_) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { if (idec->last_mb_y_ != dec->mb_y_) { if (!VP8ParseIntraModeRow(&dec->br_, dec)) { @@ -471,6 +473,12 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { MemDataSize(&idec->mem_) > MAX_MB_SIZE) { return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); } + // Synchronize the threads. + if (dec->mt_method_ > 0) { + if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) { + return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); + } + } RestoreContext(&context, dec, token_br); return VP8_STATUS_SUSPENDED; } @@ -489,6 +497,7 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { } // Synchronize the thread and check for errors. if (!VP8ExitCritical(dec, io)) { + idec->state_ = STATE_ERROR; // prevent re-entry in IDecError return IDecError(idec, VP8_STATUS_USER_ABORT); } dec->ready_ = 0; @@ -569,6 +578,10 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) { status = DecodePartition0(idec); } if (idec->state_ == STATE_VP8_DATA) { + const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; + if (dec == NULL) { + return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. + } status = DecodeRemaining(idec); } if (idec->state_ == STATE_VP8L_HEADER) { diff --git a/media/libwebp/dec/vp8_dec.h b/media/libwebp/dec/vp8_dec.h index 7b4941d65..03f4415fb 100644 --- a/media/libwebp/dec/vp8_dec.h +++ b/media/libwebp/dec/vp8_dec.h @@ -182,4 +182,4 @@ WEBP_EXTERN int VP8LGetInfo( } // extern "C" #endif -#endif /* WEBP_DEC_VP8_DEC_H_ */ +#endif // WEBP_DEC_VP8_DEC_H_ diff --git a/media/libwebp/dec/vp8i_dec.h b/media/libwebp/dec/vp8i_dec.h index d0ef67b91..fabee44a0 100644 --- a/media/libwebp/dec/vp8i_dec.h +++ b/media/libwebp/dec/vp8i_dec.h @@ -32,7 +32,7 @@ extern "C" { // version numbers #define DEC_MAJ_VERSION 1 #define DEC_MIN_VERSION 0 -#define DEC_REV_VERSION 0 +#define DEC_REV_VERSION 2 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline). // Constraints are: We need to store one 16x16 block of luma samples (y), @@ -316,4 +316,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec, } // extern "C" #endif -#endif /* WEBP_DEC_VP8I_DEC_H_ */ +#endif // WEBP_DEC_VP8I_DEC_H_ diff --git a/media/libwebp/dec/vp8l_dec.c b/media/libwebp/dec/vp8l_dec.c index 3d303fb22..0502cb9a5 100644 --- a/media/libwebp/dec/vp8l_dec.c +++ b/media/libwebp/dec/vp8l_dec.c @@ -359,17 +359,22 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, int color_cache_bits, int allow_recursion) { int i, j; VP8LBitReader* const br = &dec->br_; - VP8LBitReader br_tmp; VP8LMetadata* const hdr = &dec->hdr_; uint32_t* huffman_image = NULL; HTreeGroup* htree_groups = NULL; + // When reading htrees, some might be unused, as the format allows it. + // We will still read them but put them in this htree_group_bogus. + HTreeGroup htree_group_bogus; HuffmanCode* huffman_tables = NULL; + HuffmanCode* huffman_tables_bogus = NULL; HuffmanCode* next = NULL; int num_htree_groups = 1; - int num_htree_groups_limit = 1; + int num_htree_groups_max = 1; int max_alphabet_size = 0; int* code_lengths = NULL; const int table_size = kTableSize[color_cache_bits]; + int* mapping = NULL; + int ok = 0; if (allow_recursion && VP8LReadBits(br, 1)) { // use meta Huffman codes. @@ -386,21 +391,41 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, // The huffman data is stored in red and green bytes. const int group = (huffman_image[i] >> 8) & 0xffff; huffman_image[i] = group; - if (group >= num_htree_groups) { - num_htree_groups = group + 1; + if (group >= num_htree_groups_max) { + num_htree_groups_max = group + 1; } } - // Check the validity of num_htree_groups. If it seems too big, use a + // Check the validity of num_htree_groups_max. If it seems too big, use a // smaller value for later. This will prevent big memory allocations to end // up with a bad bitstream anyway. - // The value of 1000 is totally arbitrary. We know that num_htree_groups + // The value of 1000 is totally arbitrary. We know that num_htree_groups_max // is smaller than (1 << 16) and should be smaller than the number of pixels // (though the format allows it to be bigger). - if (num_htree_groups > 1000 || num_htree_groups > xsize * ysize) { - num_htree_groups_limit = (xsize * ysize > 1000) ? 1000 : xsize * ysize; - br_tmp = dec->br_; + if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) { + // Create a mapping from the used indices to the minimal set of used + // values [0, num_htree_groups) + mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping)); + if (mapping == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + goto Error; + } + // -1 means a value is unmapped, and therefore unused in the Huffman + // image. + memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping)); + for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) { + // Get the current mapping for the group and remap the Huffman image. + int* const mapped_group = &mapping[huffman_image[i]]; + if (*mapped_group == -1) *mapped_group = num_htree_groups++; + huffman_image[i] = *mapped_group; + } + huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc( + table_size, sizeof(*huffman_tables_bogus)); + if (huffman_tables_bogus == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + goto Error; + } } else { - num_htree_groups_limit = num_htree_groups; + num_htree_groups = num_htree_groups_max; } } @@ -419,99 +444,91 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize, code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths)); - // If num_htree_groups_tmp == num_htree_groups, the following loop is executed - // once. - // If num_htree_groups_tmp != num_htree_groups, we execute the loop the first - // time with little memory allocation in the hope that there is a bitstream - // error. If after num_htree_groups_tmp iterations, no error appears, - // num_htree_groups is probably the right value so try it out. - do { - huffman_tables = (HuffmanCode*)WebPSafeMalloc( - num_htree_groups_limit * table_size, sizeof(*huffman_tables)); - htree_groups = VP8LHtreeGroupsNew(num_htree_groups_limit); - - if (htree_groups == NULL || code_lengths == NULL || - huffman_tables == NULL) { - dec->status_ = VP8_STATUS_OUT_OF_MEMORY; - goto Error; - } + huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size, + sizeof(*huffman_tables)); + htree_groups = VP8LHtreeGroupsNew(num_htree_groups); - next = huffman_tables; - for (i = 0; i < num_htree_groups_limit; ++i) { - HTreeGroup* const htree_group = &htree_groups[i]; - HuffmanCode** const htrees = htree_group->htrees; - int size; - int total_size = 0; - int is_trivial_literal = 1; - int max_bits = 0; - for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { - int alphabet_size = kAlphabetSize[j]; - htrees[j] = next; - if (j == 0 && color_cache_bits > 0) { - alphabet_size += 1 << color_cache_bits; - } - size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next); - if (size == 0) { - goto Error; - } - if (is_trivial_literal && kLiteralMap[j] == 1) { - is_trivial_literal = (next->bits == 0); - } - total_size += next->bits; - next += size; - if (j <= ALPHA) { - int local_max_bits = code_lengths[0]; - int k; - for (k = 1; k < alphabet_size; ++k) { - if (code_lengths[k] > local_max_bits) { - local_max_bits = code_lengths[k]; - } - } - max_bits += local_max_bits; - } + if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) { + dec->status_ = VP8_STATUS_OUT_OF_MEMORY; + goto Error; + } + + next = huffman_tables; + for (i = 0; i < num_htree_groups_max; ++i) { + // If the index "i" is unused in the Huffman image, read the coefficients + // but store them to a bogus htree_group. + const int is_bogus = (mapping != NULL && mapping[i] == -1); + HTreeGroup* const htree_group = + is_bogus ? &htree_group_bogus : + &htree_groups[(mapping == NULL) ? i : mapping[i]]; + HuffmanCode** const htrees = htree_group->htrees; + HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next; + int size; + int total_size = 0; + int is_trivial_literal = 1; + int max_bits = 0; + for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) { + int alphabet_size = kAlphabetSize[j]; + htrees[j] = huffman_tables_i; + if (j == 0 && color_cache_bits > 0) { + alphabet_size += 1 << color_cache_bits; } - htree_group->is_trivial_literal = is_trivial_literal; - htree_group->is_trivial_code = 0; - if (is_trivial_literal) { - const int red = htrees[RED][0].value; - const int blue = htrees[BLUE][0].value; - const int alpha = htrees[ALPHA][0].value; - htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue; - if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) { - htree_group->is_trivial_code = 1; - htree_group->literal_arb |= htrees[GREEN][0].value << 8; + size = + ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i); + if (size == 0) { + goto Error; + } + if (is_trivial_literal && kLiteralMap[j] == 1) { + is_trivial_literal = (huffman_tables_i->bits == 0); + } + total_size += huffman_tables_i->bits; + huffman_tables_i += size; + if (j <= ALPHA) { + int local_max_bits = code_lengths[0]; + int k; + for (k = 1; k < alphabet_size; ++k) { + if (code_lengths[k] > local_max_bits) { + local_max_bits = code_lengths[k]; + } } + max_bits += local_max_bits; } - htree_group->use_packed_table = - !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS); - if (htree_group->use_packed_table) BuildPackedTable(htree_group); } - // If we have survived up to here, num_htree_groups might actually be - // that big so restart with a proper allocation. - if (num_htree_groups != num_htree_groups_limit) { - num_htree_groups_limit = num_htree_groups; - WebPSafeFree(huffman_tables); - VP8LHtreeGroupsFree(htree_groups); - huffman_tables = NULL; - htree_groups = NULL; - dec->br_ = br_tmp; + if (!is_bogus) next = huffman_tables_i; + htree_group->is_trivial_literal = is_trivial_literal; + htree_group->is_trivial_code = 0; + if (is_trivial_literal) { + const int red = htrees[RED][0].value; + const int blue = htrees[BLUE][0].value; + const int alpha = htrees[ALPHA][0].value; + htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue; + if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) { + htree_group->is_trivial_code = 1; + htree_group->literal_arb |= htrees[GREEN][0].value << 8; + } } - } while (i != num_htree_groups); - WebPSafeFree(code_lengths); + htree_group->use_packed_table = + !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS); + if (htree_group->use_packed_table) BuildPackedTable(htree_group); + } + ok = 1; - // All OK. Finalize pointers and return. + // All OK. Finalize pointers. hdr->huffman_image_ = huffman_image; hdr->num_htree_groups_ = num_htree_groups; hdr->htree_groups_ = htree_groups; hdr->huffman_tables_ = huffman_tables; - return 1; Error: WebPSafeFree(code_lengths); - WebPSafeFree(huffman_image); - WebPSafeFree(huffman_tables); - VP8LHtreeGroupsFree(htree_groups); - return 0; + WebPSafeFree(huffman_tables_bogus); + WebPSafeFree(mapping); + if (!ok) { + WebPSafeFree(huffman_image); + WebPSafeFree(huffman_tables); + VP8LHtreeGroupsFree(htree_groups); + } + return ok; } //------------------------------------------------------------------------------ @@ -916,7 +933,11 @@ static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) { #endif break; case 2: +#if !defined(WORDS_BIGENDIAN) memcpy(&pattern, src, sizeof(uint16_t)); +#else + pattern = ((uint32_t)src[0] << 8) | src[1]; +#endif #if defined(__arm__) || defined(_M_ARM) pattern |= pattern << 16; #elif defined(WEBP_USE_MIPS_DSP_R2) @@ -1555,7 +1576,6 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, if (dec == NULL) return 0; assert(alph_dec != NULL); - alph_dec->vp8l_dec_ = dec; dec->width_ = alph_dec->width_; dec->height_ = alph_dec->height_; @@ -1587,11 +1607,12 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec, if (!ok) goto Err; + // Only set here, once we are sure it is valid (to avoid thread races). + alph_dec->vp8l_dec_ = dec; return 1; Err: - VP8LDelete(alph_dec->vp8l_dec_); - alph_dec->vp8l_dec_ = NULL; + VP8LDelete(dec); return 0; } diff --git a/media/libwebp/dec/vp8li_dec.h b/media/libwebp/dec/vp8li_dec.h index ed89a02a9..2b9c95a44 100644 --- a/media/libwebp/dec/vp8li_dec.h +++ b/media/libwebp/dec/vp8li_dec.h @@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec); } // extern "C" #endif -#endif /* WEBP_DEC_VP8LI_DEC_H_ */ +#endif // WEBP_DEC_VP8LI_DEC_H_ diff --git a/media/libwebp/dec/webpi_dec.h b/media/libwebp/dec/webpi_dec.h index d0a045e70..83d7444e5 100644 --- a/media/libwebp/dec/webpi_dec.h +++ b/media/libwebp/dec/webpi_dec.h @@ -130,4 +130,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output, } // extern "C" #endif -#endif /* WEBP_DEC_WEBPI_DEC_H_ */ +#endif // WEBP_DEC_WEBPI_DEC_H_ diff --git a/media/libwebp/demux/demux.c b/media/libwebp/demux/demux.c index aec2a0a2d..2034024d0 100644 --- a/media/libwebp/demux/demux.c +++ b/media/libwebp/demux/demux.c @@ -25,7 +25,7 @@ #define DMUX_MAJ_VERSION 1 #define DMUX_MIN_VERSION 0 -#define DMUX_REV_VERSION 0 +#define DMUX_REV_VERSION 2 typedef struct { size_t start_; // start location of the data diff --git a/media/libwebp/dsp/dsp.h b/media/libwebp/dsp/dsp.h index 537ea2044..4e509bd2c 100644 --- a/media/libwebp/dsp/dsp.h +++ b/media/libwebp/dsp/dsp.h @@ -76,10 +76,6 @@ extern "C" { #define WEBP_USE_SSE41 #endif -#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2) -#define WEBP_USE_AVX2 -#endif - // The intrinsics currently cause compiler errors with arm-nacl-gcc and the // inline assembly would need to be modified for use with Native Client. #if (defined(__ARM_NEON__) || \ @@ -679,4 +675,4 @@ void VP8FiltersInit(void); } // extern "C" #endif -#endif /* WEBP_DSP_DSP_H_ */ +#endif // WEBP_DSP_DSP_H_ diff --git a/media/libwebp/dsp/lossless.c b/media/libwebp/dsp/lossless.c index 93ccecdfd..1a1523d22 100644 --- a/media/libwebp/dsp/lossless.c +++ b/media/libwebp/dsp/lossless.c @@ -23,8 +23,6 @@ #include "../dsp/lossless.h" #include "../dsp/lossless_common.h" -#define MAX_DIFF_COST (1e30f) - //------------------------------------------------------------------------------ // Image transforms. diff --git a/media/libwebp/dsp/lossless.h b/media/libwebp/dsp/lossless.h index 4a1d1e0dd..6db5fafc1 100644 --- a/media/libwebp/dsp/lossless.h +++ b/media/libwebp/dsp/lossless.h @@ -163,7 +163,7 @@ extern VP8LCostCombinedFunc VP8LExtraCostCombined; extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy; typedef struct { // small struct to hold counters - int counts[2]; // index: 0=zero steak, 1=non-zero streak + int counts[2]; // index: 0=zero streak, 1=non-zero streak int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3] } VP8LStreaks; @@ -194,10 +194,14 @@ extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined; void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n, VP8LBitEntropy* const entropy); -typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a, - const VP8LHistogram* const b, - VP8LHistogram* const out); -extern VP8LHistogramAddFunc VP8LHistogramAdd; +typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b, + uint32_t* out, int size); +extern VP8LAddVectorFunc VP8LAddVector; +typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size); +extern VP8LAddVectorEqFunc VP8LAddVectorEq; +void VP8LHistogramAdd(const VP8LHistogram* const a, + const VP8LHistogram* const b, + VP8LHistogram* const out); // ----------------------------------------------------------------------------- // PrefixEncode() diff --git a/media/libwebp/dsp/msa_macro.h b/media/libwebp/dsp/msa_macro.h index dfacda6cc..de026a1d9 100644 --- a/media/libwebp/dsp/msa_macro.h +++ b/media/libwebp/dsp/msa_macro.h @@ -1389,4 +1389,4 @@ static WEBP_INLINE uint32_t func_hadd_uh_u32(v8u16 in) { } while (0) #define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__) -#endif /* WEBP_DSP_MSA_MACRO_H_ */ +#endif // WEBP_DSP_MSA_MACRO_H_ diff --git a/media/libwebp/dsp/quant.h b/media/libwebp/dsp/quant.h new file mode 100644 index 000000000..b82e728a5 --- /dev/null +++ b/media/libwebp/dsp/quant.h @@ -0,0 +1,70 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the COPYING file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// ----------------------------------------------------------------------------- + +#ifndef WEBP_DSP_QUANT_H_ +#define WEBP_DSP_QUANT_H_ + +#include "../dsp/dsp.h" +#include "../webp/types.h" + +#if defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && \ + !defined(WEBP_HAVE_NEON_RTCD) +#include <arm_neon.h> + +#define IsFlat IsFlat_NEON + +static uint32x2_t horizontal_add_uint32x4(const uint32x4_t a) { + const uint64x2_t b = vpaddlq_u32(a); + return vadd_u32(vreinterpret_u32_u64(vget_low_u64(b)), + vreinterpret_u32_u64(vget_high_u64(b))); +} + +static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks, + int thresh) { + const int16x8_t tst_ones = vdupq_n_s16(-1); + uint32x4_t sum = vdupq_n_u32(0); + + for (int i = 0; i < num_blocks; ++i) { + // Set DC to zero. + const int16x8_t a_0 = vsetq_lane_s16(0, vld1q_s16(levels), 0); + const int16x8_t a_1 = vld1q_s16(levels + 8); + + const uint16x8_t b_0 = vshrq_n_u16(vtstq_s16(a_0, tst_ones), 15); + const uint16x8_t b_1 = vshrq_n_u16(vtstq_s16(a_1, tst_ones), 15); + + sum = vpadalq_u16(sum, b_0); + sum = vpadalq_u16(sum, b_1); + + levels += 16; + } + return thresh >= (int32_t)vget_lane_u32(horizontal_add_uint32x4(sum), 0); +} + +#else + +#define IsFlat IsFlat_C + +static WEBP_INLINE int IsFlat(const int16_t* levels, int num_blocks, + int thresh) { + int score = 0; + while (num_blocks-- > 0) { // TODO(skal): refine positional scoring? + int i; + for (i = 1; i < 16; ++i) { // omit DC, we're only interested in AC + score += (levels[i] != 0); + if (score > thresh) return 0; + } + levels += 16; + } + return 1; +} + +#endif // defined(WEBP_USE_NEON) && !defined(WEBP_ANDROID_NEON) && + // !defined(WEBP_HAVE_NEON_RTCD) + +#endif // WEBP_DSP_QUANT_H_ diff --git a/media/libwebp/dsp/rescaler.c b/media/libwebp/dsp/rescaler.c index f70e6beef..6bf387f8e 100644 --- a/media/libwebp/dsp/rescaler.c +++ b/media/libwebp/dsp/rescaler.c @@ -21,6 +21,7 @@ #define ROUNDER (WEBP_RESCALER_ONE >> 1) #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) //------------------------------------------------------------------------------ // Row import @@ -138,7 +139,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { if (yscale) { for (x_out = 0; x_out < x_out_max; ++x_out) { const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); - const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale); assert(v >= 0 && v <= 255); dst[x_out] = v; irow[x_out] = frac; // new fractional start @@ -153,6 +154,7 @@ void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) { } } +#undef MULT_FIX_FLOOR #undef MULT_FIX #undef ROUNDER diff --git a/media/libwebp/dsp/rescaler_neon.c b/media/libwebp/dsp/rescaler_neon.c index 835e646c1..b560d0cdc 100644 --- a/media/libwebp/dsp/rescaler_neon.c +++ b/media/libwebp/dsp/rescaler_neon.c @@ -22,6 +22,7 @@ #define ROUNDER (WEBP_RESCALER_ONE >> 1) #define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR_C(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) #define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC)) #define LOAD_32x8(SRC, DST0, DST1) \ @@ -35,8 +36,11 @@ #if (WEBP_RESCALER_RFIX == 32) #define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1)) -#define MULT_FIX(A, B) /* note: B is actualy scale>>1. See MAKE_HALF_CST */ \ +// note: B is actualy scale>>1. See MAKE_HALF_CST +#define MULT_FIX(A, B) \ vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B))) +#define MULT_FIX_FLOOR(A, B) \ + vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32((A)), (B))) #else #error "MULT_FIX/WEBP_RESCALER_RFIX need some more work" #endif @@ -135,8 +139,8 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) { const uint32x4_t A1 = MULT_FIX(in1, yscale_half); const uint32x4_t B0 = vqsubq_u32(in2, A0); const uint32x4_t B1 = vqsubq_u32(in3, A1); - const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half); - const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half); + const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half); + const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half); const uint16x4_t D0 = vmovn_u32(C0); const uint16x4_t D1 = vmovn_u32(C1); const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1)); @@ -145,7 +149,7 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) { } for (; x_out < x_out_max; ++x_out) { const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale); - const int v = (int)MULT_FIX_C(irow[x_out] - frac, wrk->fxy_scale); + const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale); assert(v >= 0 && v <= 255); dst[x_out] = v; irow[x_out] = frac; // new fractional start @@ -170,6 +174,12 @@ static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) { } } +#undef MULT_FIX_FLOOR_C +#undef MULT_FIX_C +#undef MULT_FIX_FLOOR +#undef MULT_FIX +#undef ROUNDER + //------------------------------------------------------------------------------ extern void WebPRescalerDspInitNEON(void); diff --git a/media/libwebp/dsp/rescaler_sse2.c b/media/libwebp/dsp/rescaler_sse2.c index 1306f8457..2d35f76ab 100644 --- a/media/libwebp/dsp/rescaler_sse2.c +++ b/media/libwebp/dsp/rescaler_sse2.c @@ -25,6 +25,7 @@ #define ROUNDER (WEBP_RESCALER_ONE >> 1) #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) +#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX) // input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0 static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) { @@ -224,6 +225,35 @@ static WEBP_INLINE void ProcessRow_SSE2(const __m128i* const A0, _mm_storel_epi64((__m128i*)dst, G); } +static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0, + const __m128i* const A1, + const __m128i* const A2, + const __m128i* const A3, + const __m128i* const mult, + uint8_t* const dst) { + const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0); + const __m128i B0 = _mm_mul_epu32(*A0, *mult); + const __m128i B1 = _mm_mul_epu32(*A1, *mult); + const __m128i B2 = _mm_mul_epu32(*A2, *mult); + const __m128i B3 = _mm_mul_epu32(*A3, *mult); + const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX); + const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX); +#if (WEBP_RESCALER_RFIX < 32) + const __m128i D2 = + _mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask); + const __m128i D3 = + _mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask); +#else + const __m128i D2 = _mm_and_si128(B2, mask); + const __m128i D3 = _mm_and_si128(B3, mask); +#endif + const __m128i E0 = _mm_or_si128(D0, D2); + const __m128i E1 = _mm_or_si128(D1, D3); + const __m128i F = _mm_packs_epi32(E0, E1); + const __m128i G = _mm_packus_epi16(F, F); + _mm_storel_epi64((__m128i*)dst, G); +} + static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) { int x_out; uint8_t* const dst = wrk->dst; @@ -322,12 +352,12 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) { const __m128i G1 = _mm_or_si128(D1, F3); _mm_storeu_si128((__m128i*)(irow + x_out + 0), G0); _mm_storeu_si128((__m128i*)(irow + x_out + 4), G1); - ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out); + ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out); } } for (; x_out < x_out_max; ++x_out) { const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale); - const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); + const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale); assert(v >= 0 && v <= 255); dst[x_out] = v; irow[x_out] = frac; // new fractional start @@ -352,6 +382,7 @@ static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) { } } +#undef MULT_FIX_FLOOR #undef MULT_FIX #undef ROUNDER diff --git a/media/libwebp/dsp/yuv.h b/media/libwebp/dsp/yuv.h index b4c5d0b6c..947b89e13 100644 --- a/media/libwebp/dsp/yuv.h +++ b/media/libwebp/dsp/yuv.h @@ -207,4 +207,4 @@ static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) { } // extern "C" #endif -#endif /* WEBP_DSP_YUV_H_ */ +#endif // WEBP_DSP_YUV_H_ diff --git a/media/libwebp/enc/cost_enc.h b/media/libwebp/enc/cost_enc.h index d731ee2fa..114823234 100644 --- a/media/libwebp/enc/cost_enc.h +++ b/media/libwebp/enc/cost_enc.h @@ -79,4 +79,4 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES]; } // extern "C" #endif -#endif /* WEBP_ENC_COST_ENC_H_ */ +#endif // WEBP_ENC_COST_ENC_H_ diff --git a/media/libwebp/enc/histogram_enc.h b/media/libwebp/enc/histogram_enc.h index 4fbb73702..ef39b7c6d 100644 --- a/media/libwebp/enc/histogram_enc.h +++ b/media/libwebp/enc/histogram_enc.h @@ -44,6 +44,7 @@ typedef struct { double literal_cost_; // Cached values of dominant entropy costs: double red_cost_; // literal, red & blue. double blue_cost_; + uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance } VP8LHistogram; // Collection of histograms with fixed capacity, allocated as one @@ -67,7 +68,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p, int VP8LGetHistogramSize(int palette_code_bits); // Set the palette_code_bits and reset the stats. -void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits); +// If init_arrays is true, the arrays are also filled with 0's. +void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits, + int init_arrays); // Collect all the references into a histogram (without reset) void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, @@ -83,6 +86,9 @@ void VP8LFreeHistogramSet(VP8LHistogramSet* const histo); // using 'cache_bits'. Return NULL in case of memory error. VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits); +// Set the histograms in set to 0. +void VP8LHistogramSetClear(VP8LHistogramSet* const set); + // Allocate and initialize histogram object with specified 'cache_bits'. // Returns NULL in case of memory error. // Special case of VP8LAllocateHistogramSet, with size equals 1. @@ -113,7 +119,7 @@ double VP8LBitsEntropy(const uint32_t* const array, int n); // Estimate how many bits the combined entropy of literals and distance // approximately maps to. -double VP8LHistogramEstimateBits(const VP8LHistogram* const p); +double VP8LHistogramEstimateBits(VP8LHistogram* const p); #ifdef __cplusplus } diff --git a/media/libwebp/enc/vp8i_enc.h b/media/libwebp/enc/vp8i_enc.h index 8972d9f10..009ccf223 100644 --- a/media/libwebp/enc/vp8i_enc.h +++ b/media/libwebp/enc/vp8i_enc.h @@ -32,7 +32,7 @@ extern "C" { // version numbers #define ENC_MAJ_VERSION 1 #define ENC_MIN_VERSION 0 -#define ENC_REV_VERSION 0 +#define ENC_REV_VERSION 2 enum { MAX_LF_LEVELS = 64, // Maximum loop filter level MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost @@ -278,7 +278,7 @@ int VP8IteratorIsDone(const VP8EncIterator* const it); // Import uncompressed samples from source. // If tmp_32 is not NULL, import boundary samples too. // tmp_32 is a 32-bytes scratch buffer that must be aligned in memory. -void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32); +void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32); // export decimated samples void VP8IteratorExport(const VP8EncIterator* const it); // go to next macroblock. Returns false if not finished. @@ -515,4 +515,4 @@ void WebPCleanupTransparentAreaLossless(WebPPicture* const pic); } // extern "C" #endif -#endif /* WEBP_ENC_VP8I_ENC_H_ */ +#endif // WEBP_ENC_VP8I_ENC_H_ diff --git a/media/libwebp/enc/vp8li_enc.h b/media/libwebp/enc/vp8li_enc.h index 5dcba9ef0..1e259eda7 100644 --- a/media/libwebp/enc/vp8li_enc.h +++ b/media/libwebp/enc/vp8li_enc.h @@ -115,4 +115,4 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality, } // extern "C" #endif -#endif /* WEBP_ENC_VP8LI_ENC_H_ */ +#endif // WEBP_ENC_VP8LI_ENC_H_ diff --git a/media/libwebp/utils/bit_reader_inl_utils.h b/media/libwebp/utils/bit_reader_inl_utils.h index 2bb9a1918..8d1249ef9 100644 --- a/media/libwebp/utils/bit_reader_inl_utils.h +++ b/media/libwebp/utils/bit_reader_inl_utils.h @@ -187,4 +187,4 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) { } // extern "C" #endif -#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_ +#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_ diff --git a/media/libwebp/utils/bit_reader_utils.h b/media/libwebp/utils/bit_reader_utils.h index 53e9db6ad..377a7821a 100644 --- a/media/libwebp/utils/bit_reader_utils.h +++ b/media/libwebp/utils/bit_reader_utils.h @@ -172,4 +172,4 @@ static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) { } // extern "C" #endif -#endif /* WEBP_UTILS_BIT_READER_UTILS_H_ */ +#endif // WEBP_UTILS_BIT_READER_UTILS_H_ diff --git a/media/libwebp/utils/bit_writer_utils.h b/media/libwebp/utils/bit_writer_utils.h index 9e9c2b729..b854fae73 100644 --- a/media/libwebp/utils/bit_writer_utils.h +++ b/media/libwebp/utils/bit_writer_utils.h @@ -151,4 +151,4 @@ static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw, } // extern "C" #endif -#endif /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */ +#endif // WEBP_UTILS_BIT_WRITER_UTILS_H_ diff --git a/media/libwebp/utils/filters_utils.h b/media/libwebp/utils/filters_utils.h index 9466030e5..891771ddc 100644 --- a/media/libwebp/utils/filters_utils.h +++ b/media/libwebp/utils/filters_utils.h @@ -29,4 +29,4 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data, } // extern "C" #endif -#endif /* WEBP_UTILS_FILTERS_UTILS_H_ */ +#endif // WEBP_UTILS_FILTERS_UTILS_H_ diff --git a/media/libwebp/utils/quant_levels_dec_utils.c b/media/libwebp/utils/quant_levels_dec_utils.c index 5c498382d..a60de3444 100644 --- a/media/libwebp/utils/quant_levels_dec_utils.c +++ b/media/libwebp/utils/quant_levels_dec_utils.c @@ -261,9 +261,15 @@ static void CleanupParams(SmoothParams* const p) { int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, int strength) { - const int radius = 4 * strength / 100; + int radius = 4 * strength / 100; + if (strength < 0 || strength > 100) return 0; if (data == NULL || width <= 0 || height <= 0) return 0; // bad params + + // limit the filter size to not exceed the image dimensions + if (2 * radius + 1 > width) radius = (width - 1) >> 1; + if (2 * radius + 1 > height) radius = (height - 1) >> 1; + if (radius > 0) { SmoothParams p; memset(&p, 0, sizeof(p)); diff --git a/media/libwebp/utils/quant_levels_dec_utils.h b/media/libwebp/utils/quant_levels_dec_utils.h index 4a59e06fe..c05376c67 100644 --- a/media/libwebp/utils/quant_levels_dec_utils.h +++ b/media/libwebp/utils/quant_levels_dec_utils.h @@ -32,4 +32,4 @@ int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride, } // extern "C" #endif -#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */ +#endif // WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ diff --git a/media/libwebp/utils/quant_levels_utils.h b/media/libwebp/utils/quant_levels_utils.h index 837bd2730..52a25a5f9 100644 --- a/media/libwebp/utils/quant_levels_utils.h +++ b/media/libwebp/utils/quant_levels_utils.h @@ -33,4 +33,4 @@ int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels, } // extern "C" #endif -#endif /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */ +#endif // WEBP_UTILS_QUANT_LEVELS_UTILS_H_ diff --git a/media/libwebp/utils/random_utils.h b/media/libwebp/utils/random_utils.h index 7b58de8c9..6688d2801 100644 --- a/media/libwebp/utils/random_utils.h +++ b/media/libwebp/utils/random_utils.h @@ -60,4 +60,4 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) { } // extern "C" #endif -#endif /* WEBP_UTILS_RANDOM_UTILS_H_ */ +#endif // WEBP_UTILS_RANDOM_UTILS_H_ diff --git a/media/libwebp/utils/rescaler_utils.h b/media/libwebp/utils/rescaler_utils.h index 1c7b31d7f..b5d176ecf 100644 --- a/media/libwebp/utils/rescaler_utils.h +++ b/media/libwebp/utils/rescaler_utils.h @@ -98,4 +98,4 @@ int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) { } // extern "C" #endif -#endif /* WEBP_UTILS_RESCALER_UTILS_H_ */ +#endif // WEBP_UTILS_RESCALER_UTILS_H_ diff --git a/media/libwebp/utils/thread_utils.h b/media/libwebp/utils/thread_utils.h index 0e88c2470..eb788f6e0 100644 --- a/media/libwebp/utils/thread_utils.h +++ b/media/libwebp/utils/thread_utils.h @@ -87,4 +87,4 @@ WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void); } // extern "C" #endif -#endif /* WEBP_UTILS_THREAD_UTILS_H_ */ +#endif // WEBP_UTILS_THREAD_UTILS_H_ diff --git a/media/libwebp/utils/utils.h b/media/libwebp/utils/utils.h index 27dc7e090..d22151b0f 100644 --- a/media/libwebp/utils/utils.h +++ b/media/libwebp/utils/utils.h @@ -107,19 +107,6 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) { PutLE16(data + 2, (int)(val >> 16)); } -// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either -// based on table or not. Can be used as fallback if clz() is not available. -#define WEBP_NEED_LOG_TABLE_8BIT -extern const uint8_t WebPLogTable8bit[256]; -static WEBP_INLINE int WebPLog2FloorC(uint32_t n) { - int log_value = 0; - while (n >= 256) { - log_value += 8; - n >>= 8; - } - return log_value + WebPLogTable8bit[n]; -} - // Returns (int)floor(log2(n)). n must be > 0. // use GNU builtins where available. #if defined(__GNUC__) && \ @@ -138,6 +125,19 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return first_set_bit; } #else // default: use the C-version. +// Returns 31 ^ clz(n) = log2(n). This is the default C-implementation, either +// based on table or not. Can be used as fallback if clz() is not available. +#define WEBP_NEED_LOG_TABLE_8BIT +extern const uint8_t WebPLogTable8bit[256]; +static WEBP_INLINE int WebPLog2FloorC(uint32_t n) { + int log_value = 0; + while (n >= 256) { + log_value += 8; + n >>= 8; + } + return log_value + WebPLogTable8bit[n]; +} + static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); } #endif @@ -175,4 +175,4 @@ WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic, } // extern "C" #endif -#endif /* WEBP_UTILS_UTILS_H_ */ +#endif // WEBP_UTILS_UTILS_H_ diff --git a/media/libwebp/webp/decode.h b/media/libwebp/webp/decode.h index 2165e96c9..ae8bfe840 100644 --- a/media/libwebp/webp/decode.h +++ b/media/libwebp/webp/decode.h @@ -42,6 +42,12 @@ WEBP_EXTERN int WebPGetDecoderVersion(void); // This function will also validate the header, returning true on success, // false otherwise. '*width' and '*height' are only valid on successful return. // Pointers 'width' and 'height' can be passed NULL if deemed irrelevant. +// Note: The following chunk sequences (before the raw VP8/VP8L data) are +// considered valid by this function: +// RIFF + VP8(L) +// RIFF + VP8X + (optional chunks) + VP8(L) +// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. +// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size, int* width, int* height); @@ -425,6 +431,12 @@ WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal( // Returns VP8_STATUS_OK when the features are successfully retrieved. Returns // VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the // features from headers. Returns error in other cases. +// Note: The following chunk sequences (before the raw VP8/VP8L data) are +// considered valid by this function: +// RIFF + VP8(L) +// RIFF + VP8X + (optional chunks) + VP8(L) +// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose. +// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose. static WEBP_INLINE VP8StatusCode WebPGetFeatures( const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features) { @@ -491,4 +503,4 @@ WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size, } // extern "C" #endif -#endif /* WEBP_WEBP_DECODE_H_ */ +#endif // WEBP_WEBP_DECODE_H_ diff --git a/media/libwebp/webp/demux.h b/media/libwebp/webp/demux.h index 555d64133..846eeb15a 100644 --- a/media/libwebp/webp/demux.h +++ b/media/libwebp/webp/demux.h @@ -360,4 +360,4 @@ WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec); } // extern "C" #endif -#endif /* WEBP_WEBP_DEMUX_H_ */ +#endif // WEBP_WEBP_DEMUX_H_ diff --git a/media/libwebp/webp/encode.h b/media/libwebp/webp/encode.h index 7ec3543dc..549cf0773 100644 --- a/media/libwebp/webp/encode.h +++ b/media/libwebp/webp/encode.h @@ -542,4 +542,4 @@ WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture); } // extern "C" #endif -#endif /* WEBP_WEBP_ENCODE_H_ */ +#endif // WEBP_WEBP_ENCODE_H_ diff --git a/media/libwebp/webp/format_constants.h b/media/libwebp/webp/format_constants.h index 329fc8a3b..eca6981a4 100644 --- a/media/libwebp/webp/format_constants.h +++ b/media/libwebp/webp/format_constants.h @@ -84,4 +84,4 @@ typedef enum { // overflow a uint32_t. #define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1) -#endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */ +#endif // WEBP_WEBP_FORMAT_CONSTANTS_H_ diff --git a/media/libwebp/webp/mux.h b/media/libwebp/webp/mux.h index 28bb4a41c..66096a92e 100644 --- a/media/libwebp/webp/mux.h +++ b/media/libwebp/webp/mux.h @@ -527,4 +527,4 @@ WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc); } // extern "C" #endif -#endif /* WEBP_WEBP_MUX_H_ */ +#endif // WEBP_WEBP_MUX_H_ diff --git a/media/libwebp/webp/mux_types.h b/media/libwebp/webp/mux_types.h index b37e2c67a..ceea77dfc 100644 --- a/media/libwebp/webp/mux_types.h +++ b/media/libwebp/webp/mux_types.h @@ -95,4 +95,4 @@ static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) { } // extern "C" #endif -#endif /* WEBP_WEBP_MUX_TYPES_H_ */ +#endif // WEBP_WEBP_MUX_TYPES_H_ diff --git a/media/libwebp/webp/types.h b/media/libwebp/webp/types.h index 989a763f0..0ce2622e4 100644 --- a/media/libwebp/webp/types.h +++ b/media/libwebp/webp/types.h @@ -49,4 +49,4 @@ typedef long long int int64_t; // Macro to check ABI compatibility (same major revision number) #define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8)) -#endif /* WEBP_WEBP_TYPES_H_ */ +#endif // WEBP_WEBP_TYPES_H_ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 21e36bf16..3e1dc47ef 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -213,7 +213,7 @@ pref("dom.requestIdleCallback.enabled", true); // Enable Intersection Observers // See WD https://www.w3.org/TR/intersection-observer/ -pref("dom.IntersectionObserver.enabled", true); +pref("dom.intersectionObserver.enabled", true); // Whether the Gamepad API is enabled pref("dom.gamepad.enabled", true); diff --git a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp index 6c470356a..59d84ced1 100644 --- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp +++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp @@ -1082,6 +1082,9 @@ nsPerformanceStatsService::GetPerformanceGroups(JSContext* cx, return false; } + // Returning a vector that is too large would cause allocations all over the + // place in the JS engine. We want to be sure that all data is stored inline. + MOZ_ASSERT(out.length() <= out.sMaxInlineStorage); return true; } @@ -1310,8 +1313,12 @@ nsPerformanceStatsService::GetResources(uint64_t* userTime, void nsPerformanceStatsService::NotifyJankObservers(const mozilla::Vector<uint64_t>& aPreviousJankLevels) { - GroupVector alerts; - mPendingAlerts.swap(alerts); + + // The move operation is generally constant time, unless + // `mPendingAlerts.length()` is very small, in which case it's fast anyway. + GroupVector alerts(Move(mPendingAlerts)); + mPendingAlerts = GroupVector(); // Reconstruct after `Move`. + if (!mPendingAlertsCollector) { // We are shutting down. return; diff --git a/toolkit/components/perfmonitoring/nsPerformanceStats.h b/toolkit/components/perfmonitoring/nsPerformanceStats.h index 6902c840d..661a78a1a 100644 --- a/toolkit/components/perfmonitoring/nsPerformanceStats.h +++ b/toolkit/components/perfmonitoring/nsPerformanceStats.h @@ -19,7 +19,7 @@ class nsPerformanceGroup; class nsPerformanceGroupDetails; -typedef mozilla::Vector<RefPtr<nsPerformanceGroup>> GroupVector; +typedef mozilla::Vector<RefPtr<nsPerformanceGroup>, 8> GroupVector; /** * A data structure for registering observers interested in diff --git a/toolkit/mozapps/extensions/content/extensions.xml b/toolkit/mozapps/extensions/content/extensions.xml index cbd05bfa9..9c8fda8ed 100644 --- a/toolkit/mozapps/extensions/content/extensions.xml +++ b/toolkit/mozapps/extensions/content/extensions.xml @@ -941,10 +941,6 @@ #endif oncommand="document.getBindingParent(this).showPreferences();"/> <!-- label="&cmd.debugAddon.label;" --> - <xul:button anonid="debug-btn" class="addon-control debug" - label="&cmd.debugAddon.label;" - oncommand="document.getBindingParent(this).debug();"/> - <xul:button anonid="enable-btn" class="addon-control enable" label="&cmd.enableAddon.label;" oncommand="document.getBindingParent(this).userDisabled = false;"/> @@ -1087,10 +1083,6 @@ document.getAnonymousElementByAttribute(this, "anonid", "enable-btn"); </field> - <field name="_debugBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "debug-btn"); - </field> <field name="_disableBtn"> document.getAnonymousElementByAttribute(this, "anonid", "disable-btn"); @@ -1430,12 +1422,6 @@ this.mAddon.install.state != AddonManager.STATE_INSTALLED); this._showStatus(showProgress ? "progress" : "none"); - let debuggable = this.mAddon.isDebuggable && - Services.prefs.getBoolPref('devtools.chrome.enabled') && - Services.prefs.getBoolPref('devtools.debugger.remote-enabled'); - - this._debugBtn.disabled = this._debugBtn.hidden = !debuggable - if (this.mAddon.type == "experiment") { this.removeAttribute("notification"); let prefix = "experiment."; |