summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--application/basilisk/base/content/aboutNetError.xhtml52
-rw-r--r--application/basilisk/base/content/browser.js24
-rw-r--r--application/basilisk/base/content/content.js28
-rw-r--r--application/basilisk/base/content/newtab/alternativeDefaultSites.json50
-rw-r--r--application/basilisk/base/content/newtab/grid.js8
-rw-r--r--application/basilisk/base/content/newtab/newTab.css112
-rw-r--r--application/basilisk/base/content/newtab/newTab.inadjacent.json3209
-rw-r--r--application/basilisk/base/content/newtab/newTab.js1
-rw-r--r--application/basilisk/base/content/newtab/newTab.xhtml1
-rw-r--r--application/basilisk/base/content/newtab/page.js24
-rw-r--r--application/basilisk/base/content/newtab/sites.js73
-rw-r--r--application/basilisk/base/jar.mn2
-rw-r--r--application/basilisk/components/nsBrowserGlue.js3
-rw-r--r--application/basilisk/configure.in3
-rw-r--r--application/basilisk/confvars.sh1
-rw-r--r--application/basilisk/installer/package-manifest.in5
-rw-r--r--application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd2
-rw-r--r--application/basilisk/locales/en-US/chrome/browser/browser.properties4
-rw-r--r--application/basilisk/locales/en-US/chrome/overrides/netError.dtd3
-rw-r--r--application/basilisk/modules/DirectoryLinksProvider.jsm1255
-rw-r--r--application/basilisk/modules/moz.build1
-rw-r--r--application/palemoon/base/content/newtab/grid.js147
-rw-r--r--application/palemoon/base/content/newtab/newTab.css58
-rw-r--r--application/palemoon/base/content/newtab/newTab.xhtml1
-rw-r--r--application/palemoon/base/content/newtab/page.js9
-rw-r--r--application/palemoon/base/content/palemoon.xhtml66
-rw-r--r--application/palemoon/base/content/sanitize.js2
-rw-r--r--application/palemoon/base/content/utilityOverlay.js4
-rw-r--r--application/palemoon/base/jar.mn1
-rw-r--r--application/palemoon/components/about/AboutRedirector.cpp2
-rw-r--r--application/palemoon/config/version.txt2
-rw-r--r--application/palemoon/locales/Makefile.in3
-rw-r--r--application/palemoon/locales/en-US/chrome/browser/palemoon.dtd (renamed from toolkit/locales/en-US/chrome/global/mozilla.dtd)0
-rw-r--r--application/palemoon/locales/en-US/chrome/overrides/netError.dtd10
-rw-r--r--application/palemoon/locales/jar.mn1
-rw-r--r--application/palemoon/modules/moz.build3
-rw-r--r--application/palemoon/modules/promise.js118
-rw-r--r--application/palemoon/themes/linux/browser.css6
-rw-r--r--application/palemoon/themes/osx/browser.css6
-rw-r--r--application/palemoon/themes/shared/newtab/newTab.css.inc2
-rw-r--r--application/palemoon/themes/windows/browser.css25
-rw-r--r--client.mk1
-rw-r--r--devtools/client/framework/devtools-browser.js12
-rw-r--r--devtools/client/locales/en-US/animationinspector.properties4
-rw-r--r--dom/base/DOMIntersectionObserver.cpp37
-rw-r--r--dom/base/DOMIntersectionObserver.h4
-rw-r--r--dom/base/Element.cpp45
-rw-r--r--dom/base/Element.h2
-rw-r--r--dom/base/FragmentOrElement.cpp8
-rw-r--r--dom/base/FragmentOrElement.h8
-rw-r--r--dom/base/nsDocument.cpp3
-rw-r--r--dom/base/nsGlobalWindow.cpp4
-rw-r--r--dom/base/nsNodeUtils.cpp9
-rw-r--r--dom/base/test/test_intersectionobservers.html59
-rwxr-xr-xdom/events/Event.cpp16
-rw-r--r--editor/libeditor/EditorBase.cpp23
-rw-r--r--editor/libeditor/EditorBase.h11
-rw-r--r--editor/libeditor/EditorEventListener.cpp315
-rw-r--r--editor/libeditor/EditorEventListener.h24
-rw-r--r--editor/libeditor/HTMLEditor.cpp12
-rw-r--r--editor/libeditor/HTMLEditor.h2
-rw-r--r--editor/libeditor/HTMLEditorEventListener.cpp24
-rw-r--r--editor/libeditor/TextEditor.cpp24
-rw-r--r--editor/libeditor/TextEditor.h3
-rw-r--r--hal/Hal.cpp90
-rw-r--r--hal/Hal.h31
-rw-r--r--hal/HalInternal.h10
-rw-r--r--hal/HalTypes.h42
-rw-r--r--hal/fallback/FallbackSwitch.cpp20
-rw-r--r--hal/sandbox/PHal.ipdl13
-rw-r--r--hal/sandbox/SandboxHal.cpp67
-rw-r--r--ipc/chromium/src/base/hash_tables.h8
-rw-r--r--layout/style/nsCSSPseudoElements.h2
-rw-r--r--media/libwebp/AUTHORS1
-rw-r--r--media/libwebp/MOZCHANGES3
-rw-r--r--media/libwebp/NEWS23
-rw-r--r--media/libwebp/README42
-rw-r--r--media/libwebp/README.mux6
-rw-r--r--media/libwebp/UXPCHANGES4
-rw-r--r--media/libwebp/dec/alpha_dec.c6
-rw-r--r--media/libwebp/dec/alphai_dec.h8
-rw-r--r--media/libwebp/dec/buffer_dec.c52
-rw-r--r--media/libwebp/dec/common_dec.h6
-rw-r--r--media/libwebp/dec/frame_dec.c26
-rw-r--r--media/libwebp/dec/idec_dec.c18
-rw-r--r--media/libwebp/dec/io_dec.c16
-rw-r--r--media/libwebp/dec/quant_dec.c2
-rw-r--r--media/libwebp/dec/tree_dec.c16
-rw-r--r--media/libwebp/dec/vp8_dec.c10
-rw-r--r--media/libwebp/dec/vp8_dec.h16
-rw-r--r--media/libwebp/dec/vp8i_dec.h15
-rw-r--r--media/libwebp/dec/vp8l_dec.c182
-rw-r--r--media/libwebp/dec/vp8li_dec.h8
-rw-r--r--media/libwebp/dec/webp_dec.c10
-rw-r--r--media/libwebp/dec/webpi_dec.h8
-rw-r--r--media/libwebp/demux/demux.c18
-rw-r--r--media/libwebp/dsp/alpha_processing.c141
-rw-r--r--media/libwebp/dsp/alpha_processing_sse2.c88
-rw-r--r--media/libwebp/dsp/alpha_processing_sse41.c10
-rw-r--r--media/libwebp/dsp/common_sse2.h14
-rw-r--r--media/libwebp/dsp/common_sse41.h132
-rw-r--r--media/libwebp/dsp/dec.c402
-rw-r--r--media/libwebp/dsp/dec_clip_tables.c13
-rw-r--r--media/libwebp/dsp/dec_neon.c725
-rw-r--r--media/libwebp/dsp/dec_sse2.c460
-rw-r--r--media/libwebp/dsp/dec_sse41.c6
-rw-r--r--media/libwebp/dsp/dsp.h140
-rw-r--r--media/libwebp/dsp/filters.c146
-rw-r--r--media/libwebp/dsp/filters_sse2.c115
-rw-r--r--media/libwebp/dsp/lossless.c202
-rw-r--r--media/libwebp/dsp/lossless.h6
-rw-r--r--media/libwebp/dsp/lossless_common.h8
-rw-r--r--media/libwebp/dsp/lossless_neon.c63
-rw-r--r--media/libwebp/dsp/lossless_sse2.c290
-rw-r--r--media/libwebp/dsp/moz.build4
-rw-r--r--media/libwebp/dsp/msa_macro.h2
-rw-r--r--media/libwebp/dsp/neon.h11
-rw-r--r--media/libwebp/dsp/rescaler.c48
-rw-r--r--media/libwebp/dsp/rescaler_neon.c24
-rw-r--r--media/libwebp/dsp/rescaler_sse2.c98
-rw-r--r--media/libwebp/dsp/upsampling.c189
-rw-r--r--media/libwebp/dsp/upsampling_neon.c52
-rw-r--r--media/libwebp/dsp/upsampling_sse2.c138
-rw-r--r--media/libwebp/dsp/upsampling_sse41.c239
-rw-r--r--media/libwebp/dsp/yuv.c125
-rw-r--r--media/libwebp/dsp/yuv.h86
-rw-r--r--media/libwebp/dsp/yuv_sse2.c349
-rw-r--r--media/libwebp/dsp/yuv_sse41.c613
-rw-r--r--media/libwebp/enc/backward_references_enc.h53
-rw-r--r--media/libwebp/enc/cost_enc.h8
-rw-r--r--media/libwebp/enc/histogram_enc.h19
-rw-r--r--media/libwebp/enc/vp8i_enc.h40
-rw-r--r--media/libwebp/enc/vp8li_enc.h49
-rw-r--r--media/libwebp/update.sh4
-rw-r--r--media/libwebp/utils/bit_reader_inl_utils.h12
-rw-r--r--media/libwebp/utils/bit_reader_utils.c2
-rw-r--r--media/libwebp/utils/bit_reader_utils.h9
-rw-r--r--media/libwebp/utils/bit_writer_utils.h16
-rw-r--r--media/libwebp/utils/color_cache_utils.c4
-rw-r--r--media/libwebp/utils/color_cache_utils.h16
-rw-r--r--media/libwebp/utils/endian_inl_utils.h13
-rw-r--r--media/libwebp/utils/filters_utils.c2
-rw-r--r--media/libwebp/utils/filters_utils.h6
-rw-r--r--media/libwebp/utils/huffman_encode_utils.h6
-rw-r--r--media/libwebp/utils/huffman_utils.c4
-rw-r--r--media/libwebp/utils/huffman_utils.h6
-rw-r--r--media/libwebp/utils/quant_levels_dec_utils.c9
-rw-r--r--media/libwebp/utils/quant_levels_dec_utils.h6
-rw-r--r--media/libwebp/utils/quant_levels_utils.c2
-rw-r--r--media/libwebp/utils/quant_levels_utils.h6
-rw-r--r--media/libwebp/utils/random_utils.c2
-rw-r--r--media/libwebp/utils/random_utils.h6
-rw-r--r--media/libwebp/utils/rescaler_utils.c8
-rw-r--r--media/libwebp/utils/rescaler_utils.h6
-rw-r--r--media/libwebp/utils/thread_utils.c63
-rw-r--r--media/libwebp/utils/thread_utils.h15
-rw-r--r--media/libwebp/utils/utils.c6
-rw-r--r--media/libwebp/utils/utils.h28
-rw-r--r--media/libwebp/webp/decode.h87
-rw-r--r--media/libwebp/webp/demux.h67
-rw-r--r--media/libwebp/webp/encode.h131
-rw-r--r--media/libwebp/webp/mux.h60
-rw-r--r--media/libwebp/webp/types.h4
-rw-r--r--mobile/android/installer/package-manifest.in5
-rw-r--r--modules/libpref/init/all.js4
-rw-r--r--netwerk/protocol/http/nsHttpChannel.cpp55
-rw-r--r--netwerk/sctp/datachannel/DataChannel.cpp5
-rw-r--r--netwerk/sctp/datachannel/DataChannel.h2
-rw-r--r--security/manager/ssl/tests/unit/test_toolkit_securityreporter.js133
-rw-r--r--security/manager/ssl/tests/unit/xpcshell.ini3
-rw-r--r--toolkit/components/moz.build1
-rw-r--r--toolkit/components/passwordmgr/content/passwordManager.js4
-rw-r--r--toolkit/components/passwordmgr/content/passwordManager.xul4
-rw-r--r--toolkit/components/securityreporter/SecurityReporter.js112
-rw-r--r--toolkit/components/securityreporter/SecurityReporter.manifest2
-rw-r--r--toolkit/components/securityreporter/moz.build16
-rw-r--r--toolkit/components/securityreporter/nsISecurityReporter.idl14
-rw-r--r--toolkit/content/aboutSupport.js22
-rw-r--r--toolkit/content/aboutSupport.xhtml6
-rw-r--r--toolkit/content/jar.mn2
-rw-r--r--toolkit/content/memoriam.xhtml76
-rw-r--r--toolkit/content/mozilla.css36
-rw-r--r--toolkit/content/mozilla.xhtml57
-rw-r--r--toolkit/locales/en-US/chrome/global/aboutProfiles.dtd2
-rw-r--r--toolkit/locales/en-US/chrome/global/aboutSupport.dtd5
-rw-r--r--toolkit/locales/jar.mn1
-rw-r--r--toolkit/modules/NewTabUtils.jsm2
-rw-r--r--toolkit/modules/Troubleshoot.jsm17
-rw-r--r--toolkit/mozapps/installer/package-name.mk12
-rw-r--r--toolkit/themes/linux/global/global.css2
-rw-r--r--toolkit/themes/shared/aboutSupport.css4
-rw-r--r--toolkit/themes/shared/jar.inc.mn2
-rw-r--r--toolkit/themes/shared/media/TopLevelImageDocument.css7
-rw-r--r--toolkit/themes/windows/global/global.css2
-rw-r--r--widget/BasicEvents.h12
-rw-r--r--widget/WidgetEventImpl.cpp34
196 files changed, 9394 insertions, 3737 deletions
diff --git a/application/basilisk/base/content/aboutNetError.xhtml b/application/basilisk/base/content/aboutNetError.xhtml
index f2de106c2..609725c9e 100644
--- a/application/basilisk/base/content/aboutNetError.xhtml
+++ b/application/basilisk/base/content/aboutNetError.xhtml
@@ -96,11 +96,6 @@
return (node.style.display = toggle[node.style.display]);
}
- function showCertificateErrorReporting() {
- // Display error reporting UI
- document.getElementById("certificateErrorReporting").style.display = "block";
- }
-
function showPrefChangeContainer() {
const panel = document.getElementById("prefChangeContainer");
panel.style.display = "block";
@@ -286,21 +281,6 @@
learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-weak-crypto-error-messages-firefox";
}
- var options = JSON.parse(evt.detail);
- if (options && options.enabled) {
- var checkbox = document.getElementById("automaticallyReportInFuture");
- showCertificateErrorReporting();
- if (options.automatic) {
- // set the checkbox
- checkbox.checked = true;
- }
-
- checkbox.addEventListener("change", function(evt) {
- var event = new CustomEvent("AboutNetErrorSetAutomatic",
- {bubbles:true, detail:evt.target.checked});
- document.dispatchEvent(event);
- }, false);
- }
const hasPrefStyleError = [
"interrupted", // This happens with subresources that are above the max tls
"SSL_ERROR_PROTOCOL_VERSION_ALERT",
@@ -370,25 +350,6 @@
document.getElementById("learnMoreContainer").style.display = "block";
- let checkbox = document.getElementById("automaticallyReportInFuture");
- checkbox.addEventListener("change", function({target: {checked}}) {
- document.dispatchEvent(new CustomEvent("AboutNetErrorSetAutomatic", {
- detail: checked,
- bubbles: true
- }));
- });
-
- addEventListener("AboutNetErrorOptions", function(event) {
- var options = JSON.parse(event.detail);
- if (options && options.enabled) {
- // Display error reporting UI
- document.getElementById("certificateErrorReporting").style.display = "block";
-
- // set the checkbox
- checkbox.checked = !!options.automatic;
- }
- }, true, true);
-
let event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
document.getElementById("advancedButton").dispatchEvent(event);
@@ -631,10 +592,6 @@
<!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
<div id="errorLongDesc" />
- <div id="learnMoreContainer">
- <p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
- </div>
-
<div id="prefChangeContainer" class="button-container">
<p>&prefReset.longDesc;</p>
<button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
@@ -652,15 +609,6 @@
<button id="errorTryAgain" class="primary" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
</div>
- <!-- UI for option to report certificate errors to Mozilla. Removed on
- init for other error types .-->
- <div id="certificateErrorReporting">
- <p class="toggle-container-with-text">
- <input type="checkbox" id="automaticallyReportInFuture" />
- <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
- </p>
- </div>
-
<div id="advancedPanelContainer">
<div id="weakCryptoAdvancedPanel" class="advanced-panel">
<div id="weakCryptoAdvancedDescription">
diff --git a/application/basilisk/base/content/browser.js b/application/basilisk/base/content/browser.js
index 38c340eea..9ec7715fa 100644
--- a/application/basilisk/base/content/browser.js
+++ b/application/basilisk/base/content/browser.js
@@ -2749,8 +2749,6 @@ var BrowserOnClick = {
mm.addMessageListener("Browser:OpenCaptivePortalPage", this);
mm.addMessageListener("Browser:SiteBlockedError", this);
mm.addMessageListener("Browser:EnableOnlineMode", this);
- mm.addMessageListener("Browser:SendSSLErrorReport", this);
- mm.addMessageListener("Browser:SetSSLErrorReportAuto", this);
mm.addMessageListener("Browser:ResetSSLPreferences", this);
mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.addMessageListener("Browser:OverrideWeakCrypto", this);
@@ -2765,8 +2763,6 @@ var BrowserOnClick = {
mm.removeMessageListener("Browser:CertExceptionError", this);
mm.removeMessageListener("Browser:SiteBlockedError", this);
mm.removeMessageListener("Browser:EnableOnlineMode", this);
- mm.removeMessageListener("Browser:SendSSLErrorReport", this);
- mm.removeMessageListener("Browser:SetSSLErrorReportAuto", this);
mm.removeMessageListener("Browser:ResetSSLPreferences", this);
mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.removeMessageListener("Browser:OverrideWeakCrypto", this);
@@ -2808,11 +2804,6 @@ var BrowserOnClick = {
msg.target.reload();
}
break;
- case "Browser:SendSSLErrorReport":
- this.onSSLErrorReport(msg.target,
- msg.data.uri,
- msg.data.securityInfo);
- break;
case "Browser:ResetSSLPreferences":
for (let prefName of PREF_SSL_IMPACT) {
Services.prefs.clearUserPref(prefName);
@@ -2846,20 +2837,7 @@ var BrowserOnClick = {
},
onSSLErrorReport: function(browser, uri, securityInfo) {
- if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
- Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
- return;
- }
-
- let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
- .getService(Ci.nsISerializationHelper);
- let transportSecurityInfo = serhelper.deserializeObject(securityInfo);
- transportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
-
- let errorReporter = Cc["@mozilla.org/securityreporter;1"]
- .getService(Ci.nsISecurityReporter);
- errorReporter.reportTLSError(transportSecurityInfo,
- uri.host, uri.port);
+ Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
},
onCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
diff --git a/application/basilisk/base/content/content.js b/application/basilisk/base/content/content.js
index 5758cb023..88e58b501 100644
--- a/application/basilisk/base/content/content.js
+++ b/application/basilisk/base/content/content.js
@@ -385,18 +385,6 @@ var AboutNetAndCertErrorListener = {
let ownerDoc = originalTarget.ownerDocument;
ClickEventHandler.onCertError(originalTarget, ownerDoc);
}
-
- let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
- content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions", {
- detail: JSON.stringify({
- enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
- changedCertPrefs: this.changedCertPrefs(),
- automatic: automatic
- })
- }));
-
- sendAsyncMessage("Browser:SSLErrorReportTelemetry",
- {reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
},
openCaptivePortalPage: function(evt) {
@@ -408,22 +396,6 @@ var AboutNetAndCertErrorListener = {
sendAsyncMessage("Browser:ResetSSLPreferences");
},
- onSetAutomatic: function(evt) {
- sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
- automatic: evt.detail
- });
-
- // if we're enabling reports, send a report for this failure
- if (evt.detail) {
- let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
- sendAsyncMessage("Browser:SendSSLErrorReport", {
- uri: { host, port },
- securityInfo: getSerializedSecurityInfo(docShell),
- });
-
- }
- },
-
onOverride: function(evt) {
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
sendAsyncMessage("Browser:OverrideWeakCrypto", { uri: {host, port} });
diff --git a/application/basilisk/base/content/newtab/alternativeDefaultSites.json b/application/basilisk/base/content/newtab/alternativeDefaultSites.json
new file mode 100644
index 000000000..018d3edcc
--- /dev/null
+++ b/application/basilisk/base/content/newtab/alternativeDefaultSites.json
@@ -0,0 +1,50 @@
+{
+ "directory": [
+ {
+ "bgColor": "#ffffff",
+ "directoryId": 10000000,
+ "imageURI": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAIX0lEQVR4nO1afXDbZh1+sxbWsbGvsrLbuBt36766sR3sOEgiuU4kx2vTpFGKm0SKsyyOlI8laUZTulLojQEHx4CyAaNnt72yrivklo1YSpxcW7YVbKXHgCvduCvroDt6o6OtLSWN1MRWX/5I4imyJMu2bPNHnrvfSZbf6P09z+/jfV+3ACxhCUsoAEouNWGlMRLri5GuZwUSe1Ug8bcFEjsjUPgHAoX/UyCxkyKJjQoU/iOhCd8WJSvW/8vpXFFsx7PGeaJsVaytul+g8KMiic+IFA7NTNB/rggk/jeRcu26RGFris3JEqIUtkFsdo2KFK6kI52pCSR2UmirZgY9YFmxeaYg1uyqFSj8lMXI5mofRb3rOwEAJcXmDS72ex8QvO43skjv3MeT2DtRX2150cgLzVUDIonF8xBh64KQ2FWRwncPejyFK4tYq/Nmoa1mPE/pnZ1ILe4TFxpdd+SdvOhxrhabXaeLTVjfsHfzSj5K4V8QKfyjnGs3P2UiCt/v/1LeyAsNlXebkbeRSOZ/Q+JCrBH/Yt7IX+qlbhS96dM+Y+dJLC6S+BWRwmazFizf5AEAQPRtHLEhukqMwo8KTfg2oamy8t+e0uvUczwDwDWxhopHBBLvElrc+wUSm/r/IN9a3ZtrbYqUe9eHTc7PZDLvoAcsi/lq2wQSO1M88k93r7ayjzdI76sxEv/5hdryT+foRknM696q9qMg5AEAQHx83WhWtU5i56PtG1E7fYkO+B4SKNd7AoWLBSEv9G3Asol8zOs+ddFTeWc+fDrXgq2MNmEP5+PdKZB/XR4RvRnWe8tjJ8+1ECsL4mA+EQ+vcCg8gHHuPjjZvc5S6guU6/3/POG5rdi+24IEv+KwEgFQ4QFU/rAKTu90pal5fCY60PlQsf22BefHwfUKD2YVfl6ACIAKfx2UX0QNBYj6arqL7bdtSIQBnYy+2iIAzg49Cid9bm3qv11sn21FggeHUwSILGQCgIljd8Kpreq+4Koqts+2QuGBmBL9FLsFSj+sgAKFnyq2v7ZCDoO7dKOvvc7fS3vcW4rts61I8OBxXdI6/UCJADgVvmGVHfMSAelgfUA6VBeQDqmv2nuzZ3rf6Y2r3SM7DB1RwmCnOsLaiGuenbWD/JwAcqI+IEPCL8H6gAwX7omADIn5z/Wqe0Iz1sgI3edSv6EjcR78OEk4jQiJCNhnlwD1ATlBmDqdCUHzcYRf3mXoSCIMXjdK95SeEAbfslUAk4iaEc1EsLnx0vNmAhw3q3mNAFvtFCBd2i8i4bdWAgYCDBkLwIMJw8antTDos12ARSTNM8JK5Amd8URAPmosQAS8Zdr41N/lIQOS0Z2/pkZe0iWoS35+rIY8rPfLvzcWgAdDljMgAr5tlwCEWgArjUxnnJXSmX8eMnQkPrH8OasCJMJgfyEE0KZxMrJ+i2WgyZq6gHTQ0BGFv+abujs//ab4gV0CqEvAar1n0gQXizj9PUNHEmHgTSFt1At4O3eCH+8D0tW2YUmoMkKvfyQzwC/vMHREegN8Tpe4zjIY55fD14+X9tgiwC8mV2ZrHS/LGOGXRd3y8aeKVee/3GrqjBIGMcMsmL/GJu6AW4+1QZRl/mKHADmipD4gz1jJHCIgw9oXJ+8zfVsi/ImXU7bDquvfI2ugZ7wHoiwDUY6BTrbTWRie+ti0d7rGrHTU5UD45StpX5iILPMZrQTD4Q0QG+2GKMckzcF28AXgaYiv7ZNesdokCb90PO0LP2TBpxQezKpFkPmb4Q/ebFlEHOWYZBY8FtriKwDXFDAHhLvr/bJi9TzQtPeycQNUI3HihkML5M9NfB4+caRTl/jHRsvtb333gTzzTUHDPonNZFkkfjVl7Zfr+MRtiMID+McICqtDvfrE2cWfHRxz2j321K155pxE84HLLWb7BK0odX75TEYTBI43hB1ch0HE554h7GJhKrkn/4wPMjfliXMSO4alcsIvx/UanZE17pcGMppkU2iL2zDt9QSZtwqu66/Okdbb88Qd7PydVFYfkGVthLWHHk1JyOteuHRjxpNh3JNjRtE3EgDlGIiwzLlqrq/MbvKtLwkewi/PalPc8PyQPDdIP8lqQvdw92qEZWbNyBqJgnD0VTTI7H74Je/1uRL/8mDr7VWjfYeJkecgdfC/6c8JavPL0+6fitn3JtdIzxbdqLPqiNMmwtAxR7BzZ+mgL2MnHGzHPQhL/wzlmCsLc64PbYPU4Xd1zwN6WdCwT/p61uQXsH6sL5TS/dOUgY4QCZRlxsuD9EDZsM/x4KDnk5ppSsqGfHehw3QjytHfQVj6HaP+U8F1wZbhMf1Dkerzpr3Sn4Ad/5/Yc2T7TQ6OOW2YBWZimAsVRzlaRoL0DMLRV/WW19SVh05+v5nbAxsPCPpZ4Jclwj95b87kF+BgO+5Bg8yFFHKZZkO68XqimoyvGd0FqUNnU/pA1yvTdbaRXwDCtj2CsszFjFLfSjZoRbEiqEqoqtE+6H2VT5LfvPfydtvJJ0V4jb537QhzxjLRdMSsimIhq5q538DNgSnbfqs0FoHrusUd6j2ScdTNyGZTNovfHa8Z6/fmnbwaTq5r+1wj0ziZrjlmvIKYP3ew9Hvk+NOPFpT8AjxHd6ypGOl607Z+YDUL5s4iChpkdq8b7b22KOTVQIPtGxet3bmQtVA6eKhnyBP6hvnPW8UAwvpq1nIdoeS6bpWY0fK3aMfJTCMc/csqtuf+YvNMi68Mt38WDTJPoSx9DGHpmaxLI8hcqBzpCiDB9ibnM87lxeaVLUrKg+1fRVimby3LPItw9G9Rlj6Bssw/EI4+i3DM+0iQPomy9JiD69hdztI7SoPtTWWvddry7w5LWIIx/gdCuvcjoZqlLQAAAABJRU5ErkJggg==",
+ "type": "affiliate",
+ "title": "Google",
+ "url": "https://www.google.com/"
+ },
+ {
+ "bgColor": "#E62117",
+ "directoryId": 10000001,
+ "imageURI": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACd0lEQVR4nO3av0tVYRzH8WOIBEVDUUIGCa32FwQ5OrS42NKeRUOTdGmoqUGiLVBqa5UG+7WUREGiEqhTDkVJEA2iYZBkxKvhHumo96o3uM9z0ucNZ7zn834+XO59znm+WZZIJBKJRCKRSGwCx3AWfbiIaxjEPYzgOd7gLWbwIb8WsFjjWrU9q3U+u1C4/0yeOZ47jOROg6jkrn25e3uji27NbzC9A9n/hWnVNbVut/hOTMZ1bSqT6Ky3+A58jOsXhE/o2Lj4FryILBaSF2gpFtAT2ygCPcUCHse2icDTtcW3YSW2TQRW0JahK7ZJRLoy9Ma2iEhvhoHYFhEZyDAU2yIiwxkeBgj6FSDjXxjN8CpA0A1cxucAWY0wkeFdgKBK/pe7H1fxNUDmTpjLMB8gqLJh631A9dF6IUD2Vsxn+BYgaF0BhSIO4WYgh1osZVgOEFSzgEIRh3EL3wO4FFnOAgVtWUChiKO4gx+BvJSqgEIRx3EXP5stVsoCCkWcxH1N3EeUuoBCEafwshlipS8AJzTxW1DaAnAEtzX5B7F0BeAgrmMphFhpClB9M3UFXwI5oQQFYB8u4H0gl3VE3QninOoxVyyWozwL4AxeB8jdjqWgT4M4jUcB8nbKfKj3AUN4gN8BshphLtQbobIyEeqdYFkZzTAc2yIiw+lcQDoZSmeDe/t0ON+gPIltE4Fnxa3pnp8QacFYbKOAjCnOCOUldKhOUO12Nk+JFUroxFRkwWYypd6cYKGEVvTbfZOil2w3KVqjjHZ047xqKRWbZ4XHVed2Z/2d5a0167vYgHC9z6/df9bWs8L9uXO3RmeFE4lEIpFIJPYKfwAcall+TY3q/wAAAABJRU5ErkJggg==",
+ "type": "affiliate",
+ "title": "YouTube",
+ "url": "https://www.youtube.com/"
+ },
+ {
+ "directoryId": 10000002,
+ "imageURI": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACT0lEQVR4nO3bzWsTQRgG8PlPHMVLqRVMoQiFehJyUBAFtRCFHspExaaSoFg8CMGPSg+R3kQhh3osIbOlMVrbGKtrsbYESTbB0gqNVGu1WCkWutnXg+ihQjqxi7Oz8w481533+V32iyGEEEIZ76Rho0SZ4ewOG+D3UMatXSx9nPwqb5ySPZC0dPMzhDJelD6IrDCjQijjtvRBJIWGeY3IHkJ2EED2ALKDALIHkB2lAJoujkIwnoNQwoQL96aha3AKQgkTTtyZhKM383D4+gQEoll/AQRiWbg1XILZ+VWwaw6IrE3bgZbejNoAe8+PwEC6DOsbm0Klt679lxQGCESzMD335Z+KKw+wrzcDpcVvOyqvNMCwubjj8soCnBx44Up5ZQGeFZf1BWi7/BhqjthtzpcAseRsQwVrjgNzS9/hZWUFJq3Pf6U5MqoWQHJ8Qbh8aqoKB688cWVfzwBMvP0kVN6srMCec+7t6xmAmfmvQgCRBzOu7usZgHJ1TQjgyI283gCHrj3VG6C9bwwBEAABEEAtgAPRR9A3VKibpdUfQgD9KWvba529+8pbAMF4TqicW+th/r3eAP0pS2+Anvtv9AY4dvu53gCtMfGfI74DWN+wG5rNdwDl6preAGOFj3oDJMcXvAfQHMlAKGHWTeWD2KPw1aFC3et0NPi9wDPvAq/fif0LDMZzru6LALKLIwACIAACIAACIAACIAACIAACIAACIAACIMD/BvDKwUkZAJRx2zNHZyUBFAntTp+WXV4iQCf5c3yecUsXAMq49bv8Txsl6ZCTabOAAAAAAElFTkSuQmCC",
+ "title": "Facebook",
+ "type": "affiliate",
+ "url": "https://www.facebook.com/"
+ },
+ {
+ "bgColor": "#ffffff",
+ "directoryId": 10000003,
+ "imageURI": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAA/CAYAAABQHc7KAAAEyUlEQVRoge2abYhVRRjHf7veVqSFhIQwa7E3ojXNpSiNgl0S+tAHKUjohbQohUgqKKwMSXpbsATdqOgFU4zKpAzMioploxI/WFBZmhRlL/S2lbpsudvd24dzjve5c58558ycey9B84MB95x5/vM/d+bMzDNHCAQCgUAgEAgE/rf0AOd6lJmKVrdDfI8SfxawIKNcEscfa8TOzBFrlj6Aimd5XnmAbx01TD5xiL3IiH3Y8zm4DXgaGALGMip/DDwHDACXKQ9wA/AiMJyi8T3wAnCvEr841t9tiR2JY/uB443YC4BHgA3ApyntTxD90FuAlaaBU4EfLIHvKIZtnAT8ZtE5O6fGCiNuFJiTM7YNWKe0PQScmRV8ncX4+zkbT1hq0bkyZ/wyI+5ux/bPM+I/ACbnCSyhv8tloMvBQAnYr+h8mDP+PRHzGXCMQ9sA14j4ceAMl+A70HtvjaMJ22jqy4i70Kh/sWO7AO+K+Jdcg6cCh6k3/gfQ6aBTAr5UdN7OiHtL1H3NxXhMN9Fkl2jM89BgPXrv3eKoc71Fx2ZqvqhTJv+kKRkQGjs94gE4PTZgGt9DNMvmpQR8pehst9R/Q9TZ5OG7EzgkNK720DjKNvTeu9RRZ4miMUH9bnCeuH8EOMXD881C40egw0PjKL3oP8Cbjjq2FWGrUW+HuDfg6XmP0NA2W060GYKy97odtbQVoQzMiu+fL66PACd4+O0VGqPANA+NOm5CHwVPOeqUgH2Kzub4/uvi2gOeXrcU8GdlCtG7ZBr/C5juqHWtojMOXCX+HgaO8/B5YqyV6GjZpjf3oI+C+x11JgF7FZ1/xL/v9PS4WmgMempYsW2MfsdtYwTRsqT9mBXgANGIc6WD2lG60EMjk0fRTS931GkHPrdo3ejpbZHQ2B+30XC6iNZm0/Q3RBOcC7Yc4WRPb0NC43ZPjVxsRDe+yFHHHLJJWevhabaIP0z0ujaNWdQmGUn5yEPrPkVnBPe1+0kRv97DhzPb0UdBr6OObZv9kIOGnJzLRPlL0+lFN+6yPe5BH0kV4E/yD+PlIm6bQ/uF2Um98Qlgbs74V5V4WVbl0GgDvsB/BBbiCnTj2lG5yVyqvX+QaOSYOsNk7y8WiPo+c1Ah2tFPesbJTmFfEfX7qU2BZVmRoSPnkMU+D1EUW5L0WErMHKq9P0o149NeqZ+w7wq7qO77f02p11Qmo6/laWnoVlFvnbh+uaJTAW616Dwo6rjmIw3lLnTjminZ+38DM8Q92yv1HfUnOh3AL/H9I7hnpA1lKrXnb0nRkqSXxf0nFC3bK7XMqCdT6o2NeIiirEE3Lvfks6kesI6hf1m2nTt8TW2uIeeLhub8vsxAT5IOUB2+8qTm2RStlYqOnOV7xLXBRj5EUWxJ0hKic/2k98dJ367azh32Es0Tz4hrTcn5fZE9I8s+ajc6m20CgrUWrdVEK0yFJub8RRhEN56UMjk+TVO7xtuK6yFMS1hIuuk82+SETSk6h3A/hmsJ7egfPypEh555ej/hHOzZYktyfl9keiqLzzc+LUlqWc7vSyfRJ3Rpegw4zUOrj/ofoKU5vy/91Jp+vIDWLkPL/J9h/0mmAT9TXa58vvIkzKe6ydpQ3FogEAgEAoFAIBCI+Rf5q90lTPZHIwAAAABJRU5ErkJggg==",
+ "title": "Wikipedia",
+ "type": "affiliate",
+ "url": "https://www.wikipedia.org/"
+ },
+ {
+ "bgColor": "#400090",
+ "directoryId": 10000004,
+ "imageURI": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAD3ElEQVR4nO3bS4xecxjH8WmLBVVEx63JBIkEISkhJqURpAsZQioWqpeNSxraYlKpSwiDIRY0aSakqgS9qHRBIhKxYdFFFxWXIGkilYZEUCKj4zLzsfi/LN55zpiZc/lr+/6Ss3nfc57ze77n9r88/y7swxaswgLM7jpMhTlYiNWtnPd1Ga9RfIVtuB+L0J3b/FSFeejDQ9iBvRhrTzYCUKTv8RFewlrcgAtxQsYk5+Ii3IQHsBm78ONkk5oKgIn0Mz7BO3gBA7gHS3EtLsXZre1UnITj2pI5vvV7D85BL67DCvRjEJvwHj7HcBXGqwJwyKoDILeB3OoAyG0gt8oAGMYj0qdnJ17DY3i2vK1CPYmn8Cq2YwgP4rfpBix7BwwE3+aZ2F0ybqQPMSM439NlgpYFMILzAlO9glZXCf2F+cF5LsafZQJX8Q4oujKbK4j9j4aC+EdhT9nAVb0Ebw8MduNABbF/wMlB/LUVxK4MwE84JTC5uoLYK4O48/BrBbEr/Qy+XnCbfloi5h7MCuJurcSxagGMYWFg9qr/SbxQVTeEiq7Ym9OI9UYQ52ipJ1iZ6mgJ3h0Y7zG17usvOC2I01+12ToAHBCMIGHdFGKsCo4/QwJTqerqC2wMEjgGX0zi2KLH6JU6jNYFYBSXBElc/R/HjaE3OO4y1bYs/1WdvcFd4hbilgmOie6cGa1Ytaju7vDSIKHTxc9yUYtvWZ0G6wawH8cGSa0J9r0t2G92K0ZtamJA5PEgsfaOTNHjMlC3uSYADKMnSG6B9GIr6uqehYN1m2tqSGxre4KtJDdhfcF/O5ow1hSAMVweJNmNOcHvlbb3J1KTg6K7MTO62m3Jz1LBQMdk1fSo8IpJALizSUNNA/jWBNPvOFGahG1MOeYFnpgAwHNNm8kB4CDODJI/F380bSbXzNAzAYD1OYzkAjAYABjKYaQDIMdJxQDqnFMsVC4A6wIAgzmMdADkOKkYwKM5jOQCcFcAYCqjxpUpF4Bovu+IB3BfDiO5AIzrFWJlDiO5ACzpABgP4I4cRnIBWBwAWJLDSC4AfR0A4wHcksNILgCLAgB9OYzkAnDFkQ5gDZbj3ta2XCp5bVydYuncBnKrAyC3gdzqAMhtILfqBDCCb6SZ3velatGXsUFa5NC+vdjatrf2/QAfSyUyv9dlsgyAEXyGt/G8VBl+PS7A3PaGTllJCy7n40Zp8GQD3sWXSgCaDIBRqcBxGx7GYmll57hixlySaojPx83SuqW3pLXC0wKwX7oF+3GloILjUJE03X6NtAh8J76LAOzFRtwqKGY63CStX14mLen5+m9Vgqdbrd+9cgAAAABJRU5ErkJggg==",
+ "title": "Yahoo!",
+ "type": "affiliate",
+ "url": "https://www.yahoo.com/"
+ },
+ {
+ "directoryId": 10000005,
+ "imageURI": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAJdklEQVR4nO1ba1QTZwL9iCY8hCDxDUpYOIUDBOVZAlJ5NQXRFlEQ8YGiRaqESlhxeRQ3FAWURRC6FYglqBHTEaI8Eg+CRMRatfKwLNL6oqer1h57XEWYbwJK9sdKixiSmRCCbrnn3D8w351770wy3zd8ADCJSUxiPMHhcPS3bdv2/tq1a9MWL16MODs7t5iamt4zMjLq0dfX76VSqU8sLCzueHt7S+3t7QtjYmLWJyYmzp1o32NGSUmJd0BAQLmRkVEPAEBOhCQS6bm3t7c0MjIyHACgMyEB1AGCILTY2NgUOzu7fwGCoUfj/Pnz/x0XF/fXgoICXW3nIYTs7Owlpqam94CGgo+ktbX1j4mJiY7azIQbMTExu3V0dF6AcQo/RF1dXYggSIj2kuFAfHx8Lhjn4ODVElCxWOygpXjKkZWVxQZaDD9EOp3eXV9fb6yVkKOho6Njgb6+fp8ig9pgfHx8gjZyjgYdX1/fhtHMqSKJRHpOJpNl6o4HAMidnJxatJJUEWpraz3xmBxOExOT30JDQ/+elpZmD14+26uqqubExcVFzJs3T53H5uCJEydMtZN4BKKiovKJmA0KChLu3bt3zmh6Bw4c0F+3bl0BEU0AgLygoCByXAKqgq2tbSdek0FBQTV4dZlM5kW8ugAAOZPJ/IeGIuHH9evXp+no6DzHa7K+vt4Lr3ZiYuIOvLoAALmnp6dQQ7HwIzc31xqvQRsbmy5AYC6fnJzsjlcbACD38/M7p5lUBBEeHp5lbm7+E4lEUnonREdHpxPRLSwsNFWmN5Kurq5XNZNITfj4+EwtLCw0dXFxcebz+UFhYWFbmExm6qZNm/IjIiKyampqDIjonTp1ajp4mwrQNP70BfD5/D9PAcXFxQZcLteOwWCw9u/f/3FwcHC6paVlOfg/K4CUlpbmEB0dvSEkJCTLxsamwtnZuXXmzJmPAACDgEBYRXxjC8jJyfFYtmzZYWNj48dgjCGV8Y0qICsryyQiIiKVTqf/BMYxNHgTC8jPz/+ISqU+AVoKDt6kAnbs2MGeMmXKANByePAmFBAbG5utyJi2OKEFJCcnx+MxqYizZs361d/fvyw9PX0bg8FgZWRk2FZVVc1pampaQERnwgoQi8VLVK0DRpJMJstWrlx5hMPhvMflckmKdN+amSDRdbuenl5fRkaGnyrdt6KAsrKyD4iYpFKpTy9cuPAuHu23ogAmk9lIxGRCQsLneLVLS0tnEdHWegFisXgu0b8ANTc3W+LVT0pKsiSirfUCDh06tJyIQSsrq5tE9PPy8jyI6Gu9gMDAQA5Bg9VE9Hfu3BlFRJ/BYHSMPRUBsNnsfUQMksnkciL6q1ev5hHRNzQ07AHa3D9A9N19QEAA7lfiAAAdOp3eTUQfACBHEMR87MlwgmgBZmZm9wHOK1RUVLSFiPYQd+/eHaOheKrB4XCyiBrk8XguqnTb29vNDAwMeolqAwDkCxcuvKbBiMoREhLyKVGDy5cvr1Cm2d3dPd3Ly+sCUd3h3LNnT7xGg46GoqKiQHUMbt68uZjL5VJG6qWkpPjS6fS76miO4Ivm5maVd9qYUV5ePlPdtb+FhUV3cHBwkbm5efrGjRvz7O3tr2og+O90dHRslUqlUxX5lkq5U7HmJEtUsnTxwG0kEJ7b4Cer32ArlXIVHq8ULBarVpPGNcng4GDP4V6xloxArNq3oq+M9hTlUeSvsfwvPxMuoKGhwWO8N0RRKBSM6Bg6nf4jgiC0zk6Egl3czsYQhxsKQ48g4QIAAMDf3//0eIWn0WiPjh075jx79uyHeMfY2dl1IAgyFwAAZA1rjqE8ihw9rPscrXRp7xO5lckaN6X0t+dt7m/LiYanPI+iPPLgmApoa2t75+W7fY2GX7RoUcvx48fpAAAgEom88NwJLBbr65ycnGlD3gZuli15VhfC6JZy9Ubzj1W6to6pAAAAEAgEDsbGxv/RVHh3d/ezEomEOvwcqamp6crGsNns/NHeLg0HPPOhV98Pf2ynQRHG+ZcFDKpdAAAAFBcX+6qzF3gkly5dqjCIVCrVs7e3v6RozKpVqw6q8idrybCFonfrUB5FDqsWfzv0c1jh2IHyKHIotL0J+lsyY7CqJXmyO4hamw/Ly8vnhIeH51Op1KdEQtNotN9WrFjxpVAodFOmv337dkMmk1k9NI5CoWCZmZk7EQSZouj4bilfT/ZtUjhW4yNCDxv0ozyKHJaZ9Mq+S1sDAACdnQgF8o1RlEeRy5picsDA3dPv9QnMHqI88iAUudYNdJV4q1NEXFyc7q5duzZ4eXmdtLKyukUikV6ZL1Cp1CeOjo6tHh4eRVwudwWfzx/1MzoSXC53alRUVCaLxapjs9kBio55fC3bGPvm0wRUQL/3yjc9n9Yz0HX090zolTSP//2OPIjdEVkDAAB42nmYJjsbWjo0CEMcfoCNkXvR5lh3BAlT2LQqhIWFTZFIJFSJRELdunUrWR0NVXhc/zdj9MxHa6B4qRAemfHasx6rYUnQjn8uGD5G9k3CHpRHkcvqQk+8Joh1lX2AHl9wf+RkAWtYvx9eSvaWSn2Iz5w0jId1O6fJLn8Wila6iVCe/oCiZ3sff8YT7CLnE6BgJQoRhxtoqcmz3l8vK9629+xW6Sx4dnUmLJv55DXxo3MeQ8ThDKxlfS77Pm8F1pxkqegkmsItSZxu75nAhf1NMZFY47ov4MlFzejLz69ClhrB/vObc3uuZM5QpIf9fM4K5VHk/W25sSpP3tdaaArPrBSgJbovlM6m+LQeWO13HqtwO4i1Zn0CRZ5+2Hf7bB5cK8a9P6hbytfDOgqsMJErC7vyWRw87VUERR5X0VJDiGc2h/IocljL+rr3Klfpv9pg9xttsLOrVIcfDtltEQOtcP0CFZg/wGvmjysyvQ8VmP8ChTa3McThBiZya8NEbm3YSUYXFNrcRgXmv8Ay2jOUp0tMd9gdidWHFsiuH2QQCqUOuFwuSXY5ZT1a6dyullkNEiKMLky6NaYTeX2JrRXILqcslIkDk2GFYyP6lSE27oGPzHiKVTiJZdV+qf2dh50mJPRo6Jby9bBLycvRSpcCeNLpe7SEovw7Aw+/MpDBUx5XsNqAbHgp2buzc4KutDp4dHGXEVq3xh02fbwFq2Htg5WuQljlcwFWLOqAJ97p7hOYPewTmD2EQuu76Emn67DauxmtdEawap8ceH5TNFofznxQs5XQBstJTGISk1AX/wUPVWOeSpK50AAAAABJRU5ErkJggg==",
+ "title": "Amazon",
+ "type": "affiliate",
+ "url": "https://www.amazon.com/"
+ }
+ ]
+}
diff --git a/application/basilisk/base/content/newtab/grid.js b/application/basilisk/base/content/newtab/grid.js
index 415a25933..b6f98fa17 100644
--- a/application/basilisk/base/content/newtab/grid.js
+++ b/application/basilisk/base/content/newtab/grid.js
@@ -9,6 +9,7 @@
*/
const GRID_BOTTOM_EXTRA = 7; // title's line-height extends 7px past the margin
const GRID_WIDTH_EXTRA = 1; // provide 1px buffer to allow for rounding error
+const SPONSORED_TAG_BUFFER = 2; // 2px buffer to clip off top of sponsored tag
/**
* This singleton represents the grid that contains all sites.
@@ -181,15 +182,18 @@ var gGrid = {
// Create the site's inner HTML code.
site.innerHTML =
+ '<span class="newtab-sponsored">' + newTabString("sponsored.button") + '</span>' +
'<a class="newtab-link">' +
' <span class="newtab-thumbnail placeholder"/>' +
' <span class="newtab-thumbnail thumbnail"/>' +
+ ' <span class="newtab-thumbnail enhanced-content"/>' +
' <span class="newtab-title"/>' +
'</a>' +
'<input type="button" title="' + newTabString("pin") + '"' +
' class="newtab-control newtab-control-pin"/>' +
'<input type="button" title="' + newTabString("block") + '"' +
- ' class="newtab-control newtab-control-block"/>';
+ ' class="newtab-control newtab-control-block"/>' +
+ '<span class="newtab-suggested"/>';
this._siteFragment = document.createDocumentFragment();
this._siteFragment.appendChild(site);
@@ -270,6 +274,6 @@ var gGrid = {
this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth +
GRID_WIDTH_EXTRA + "px";
this._node.style.height = this._computeHeight() + "px";
- this._node.style.maxHeight = this._computeHeight(gridRows) + "px";
+ this._node.style.maxHeight = this._computeHeight(gridRows) - SPONSORED_TAG_BUFFER + "px";
}
};
diff --git a/application/basilisk/base/content/newtab/newTab.css b/application/basilisk/base/content/newtab/newTab.css
index 64b3ed7ef..658ad2ed3 100644
--- a/application/basilisk/base/content/newtab/newTab.css
+++ b/application/basilisk/base/content/newtab/newTab.css
@@ -122,6 +122,10 @@ input[type=button] {
pointer-events: none;
}
+body:not(.compact) #topsites-heading {
+ display: none;
+}
+
/*
* If you change the sizes here, make sure you
* change the preferences:
@@ -136,6 +140,12 @@ input[type=button] {
width: 290px;
}
+body.compact .newtab-cell {
+ width: 110px;
+ height: 110px;
+ margin: 12px;
+}
+
/* SITES */
.newtab-site {
position: relative;
@@ -165,13 +175,16 @@ input[type=button] {
}
/* TITLES */
-.newtab-title {
+.newtab-sponsored,
+.newtab-title,
+.newtab-suggested {
overflow: hidden;
position: absolute;
right: 0;
text-align: center;
}
+.newtab-sponsored,
.newtab-title {
bottom: 0;
white-space: nowrap;
@@ -179,11 +192,103 @@ input[type=button] {
vertical-align: middle;
}
+.newtab-suggested {
+ border: 1px solid transparent;
+ border-radius: 2px;
+ font-size: 12px;
+ height: 17px;
+ line-height: 17px;
+ margin-bottom: -1px;
+ padding: 2px 8px;
+ display: none;
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ top: 215px;
+ -moz-user-select: none;
+}
+
+.newtab-suggested-bounds {
+ max-height: 34px; /* 34 / 17 = 2 lines maximum */
+}
+
.newtab-title {
left: 0;
padding: 0 4px;
}
+.newtab-sponsored {
+ background-color: #FFFFFF;
+ border: 1px solid #E2E2E2;
+ border-radius: 3px;
+ color: #4A4A4A;
+ cursor: pointer;
+ display: none;
+ font-family: Arial;
+ font-size: 9px;
+ height: 17px;
+ left: 0;
+ line-height: 6px;
+ padding: 4px;
+ right: auto;
+ top: -15px;
+}
+
+.newtab-site[suggested=true] > .newtab-sponsored {
+ background-color: #E2E2E2;
+ border: none;
+}
+
+.newtab-site > .newtab-sponsored:-moz-any(:hover, [active]) {
+ background-color: #4A90E2;
+ border: 0;
+ color: white;
+}
+
+.newtab-site > .newtab-sponsored[active] {
+ background-color: #000000;
+}
+
+.newtab-sponsored:dir(rtl) {
+ right: 0;
+ left: auto;
+}
+
+.newtab-site:-moz-any([type=enhanced], [type=sponsored], [suggested]) .newtab-sponsored {
+ display: block;
+}
+
+.newtab-site[suggested] .newtab-suggested {
+ display: table;
+}
+
+.sponsored-explain,
+.sponsored-explain a,
+.suggested-explain,
+.suggested-explain a {
+ color: white;
+}
+
+.sponsored-explain,
+.suggested-explain {
+ background-color: rgba(51, 51, 51, 0.95);
+ bottom: 30px;
+ line-height: 20px;
+ padding: 15px 10px;
+ position: absolute;
+ text-align: start;
+}
+
+.sponsored-explain input,
+.suggested-explain input {
+ background-size: 18px;
+ height: 18px;
+ opacity: 1;
+ pointer-events: none;
+ position: static;
+ width: 18px;
+}
+
/* CONTROLS */
.newtab-control {
position: absolute;
@@ -228,6 +333,11 @@ input[type=button] {
margin: 40px 0 15px;
}
+body.compact #newtab-search-container {
+ margin-top: 0;
+ margin-bottom: 80px;
+}
+
#newtab-search-container[page-disabled] {
opacity: 0;
pointer-events: none;
diff --git a/application/basilisk/base/content/newtab/newTab.inadjacent.json b/application/basilisk/base/content/newtab/newTab.inadjacent.json
new file mode 100644
index 000000000..53fb542af
--- /dev/null
+++ b/application/basilisk/base/content/newtab/newTab.inadjacent.json
@@ -0,0 +1,3209 @@
+{
+ "domains": [
+ "rp5slFCxq/e7hYhXJCd0vQ==",
+ "2rEimAJDNX5g8HPZehOrGg==",
+ "nvLEpj6ZZF3LWH3wUB6lKg==",
+ "9Cqd4Lm3VvXuJxz79Bbqyg==",
+ "vNRy4LR+7TOKTixqsr5ybw==",
+ "N4zSgsZCo6Z4XRwZ4fu8WQ==",
+ "jsDtRfVbMsFg3KkEl2UiZQ==",
+ "TckkKpiq0a6J6NTw7uOZqw==",
+ "9Or7IAYuuIgZA370w9rNIg==",
+ "ul8WvOjCkxTz9LjT4RqTHg==",
+ "ZGJrbwb5878Nsqm0z+A7nQ==",
+ "5iT64HTeeG5SIFXG7A9o3w==",
+ "YSeSEghPe1kV6g8ghFcNAA==",
+ "0jIUl1NDmJZQkDY12VDeIQ==",
+ "aos6UyDyIw0R1nTK5wTawA==",
+ "G1xxubsq65ugK06UT2DO5A==",
+ "lbhavoDrDPP/8m0onwo63w==",
+ "ObcLsjW0SkdvY0nkZmiTGQ==",
+ "FHZ5084LC0nTAzZlnSKN3Q==",
+ "cdEr+0Fv5iaVZzalZToseg==",
+ "Co8WbNYbCPTFPcHpeK3hRQ==",
+ "qXSzhCEhByLQq9N84tqV+Q==",
+ "h3ufhRk5IEFaNH11rIACtQ==",
+ "fQ1PJ/JwazIaYoy/zy49QQ==",
+ "zAJqfbn54Nsm2ddGtkb59A==",
+ "ixPM9T8ik/gWGZ7BRIcaig==",
+ "/E9pwA3E3hVAZoYq3FmCyw==",
+ "U6ygonI8CxpruhpGB2+Q6A==",
+ "Igi4voB8oVMVw6WUeDSjZg==",
+ "jtuHIJhwoTGzavFpM7ilNw==",
+ "eBvTV27n6Gs+ZsBkpVynvw==",
+ "sFbzw0AUOGG0NEzkaSxVDg==",
+ "yAkIS+Ezj6woEff9YvdO7Q==",
+ "IP1+BwG6q60QzDADi8j7oA==",
+ "Q/teQEBFepHtwZ7UHa2TEA==",
+ "B1vDep5a1Gok5Gnth39+LA==",
+ "cyEIyQ2MZaPGf+K1x9Bbkg==",
+ "aaM+oEJnF4/nwMWyXJU8rA==",
+ "qpDNIpxah8FUiqXm5IRaUg==",
+ "ZTeJ35gMPqIv2WWbeNyIEg==",
+ "nzoAGQAnC/Xgg5PmOgXqkA==",
+ "J5pJDuNi3cqQiyaRJAJk4g==",
+ "2vqN53BXhXzPrKYsh6QH1A==",
+ "QlrzHNYxCwCBMVENvbXjQA==",
+ "Ou2HGn43nmsL3RWSNvMdXw==",
+ "3qk9lsvGTMqVMAZW+xihfw==",
+ "RncMe42RB2bhmUbYtGVnKQ==",
+ "hzNXR6dqPq1+vf4Qh5ByWA==",
+ "sRq3S2ZRs3H39cEQHv4Vig==",
+ "B4ThUBTVJOUPyOsHxikHXA==",
+ "A2lU9GkAdSibLO1JJfFnIA==",
+ "ef3HNkSvuWQrAzkuty2iqg==",
+ "yKDiRM6bf2xc0QXIwHYuaA==",
+ "AdCk4ccJuhA0bIT/61J+RQ==",
+ "UXvAZ7ULCVz2f505K0Wkvg==",
+ "ueKWblrOwVJNgiOvkXKLBQ==",
+ "s8u/jPuBAxu1d18HfV5Z0g==",
+ "hUT0Uc5YMUdNZQEGLz4hJw==",
+ "6jo/phmMTrEXKrNRsionGQ==",
+ "s/Ea/3fkyJ9honzPJkgEQQ==",
+ "hgu2/Jf+WrQAHfO+asW2zw==",
+ "kiVuTNwZ1r2lqYEZxIHyiQ==",
+ "24T5KVrVE2mYwJ5Goj3xJw==",
+ "fiWBVlfj97GGjEvf/Q9Spg==",
+ "5VWdlvJe7eoXMGkTtHzCUg==",
+ "+cFQxKa5RWVtc1z00Jujew==",
+ "nVa+rLH5p+yXBksLwQsjRQ==",
+ "5tyI6bMdb3tMIi4ewvr/SQ==",
+ "S6Roj31yS5bZbSFcd3f4Hg==",
+ "uW1Zl8iuEF8ZT/gwCBEqwA==",
+ "YwL+FJgxlZ8JVig+9iP5Cw==",
+ "ThIYK/mQsp9cMf8+rws/4Q==",
+ "w0oSxOhRG6kE9B868aoYVQ==",
+ "DJUDGQ0J32dF1kfItyxALg==",
+ "34/ab69lPkuAKt6WBxJPpA==",
+ "25jH4C9apgqWZGZP15lM6Q==",
+ "GxvwleSaSwILD1pG9k9buA==",
+ "YRAMt2ArEINo83ms6AqJ0A==",
+ "15HyTJNoMYzi3XCkeU5Z7A==",
+ "/SqjXGD+TKC90uz1vsjqUw==",
+ "karhKOknkhtg/LSFo9BGRA==",
+ "+tD1d0t3vfJvc1hUAvTT4Q==",
+ "rkaKbtlnyVr53D0rexLqdQ==",
+ "fAugw4rtnXzzRXfC1wRgOQ==",
+ "RgxoepF/XOwIsGat5r5HpQ==",
+ "Y49/EnzVz3ugXCYxFjFN7g==",
+ "tHMyzBm/2wNDw7TeNeujbg==",
+ "LlqzYV4uZpiJy4ORWPSekA==",
+ "M3Huar7/ded9OGgDwJhZgw==",
+ "QkNNATSx/PJ1XjgZyTtkUQ==",
+ "skVw0v6Wx00sfHAScPK1Bw==",
+ "v1gsIvg+C68T9wixMzL2sQ==",
+ "hDL75EXhl7BaYnAxkoGwbw==",
+ "tReG97snx2ESpXbfllCL7Q==",
+ "EiZBXR15dT1TMrkgkzmkvw==",
+ "5hRHirfD90/sdp0ILJQU8A==",
+ "rabElvtYtG0jW6dxAOHofg==",
+ "JpxoTRKWN+SEeBQ453R1YQ==",
+ "Faz4Lm0cpjvF0IjVkHiZMg==",
+ "jGErFAIoXx+50KFpVIGZiA==",
+ "5GzBkduKpUX7u1uwtYIFug==",
+ "cRBe0J9/KWRX19N2vPkCiw==",
+ "t/7g8t4Kr3/+SCnOn3XFWQ==",
+ "sd08c6jUXs5/hxND0fBkPA==",
+ "nTxKpqIdnHNdpDk7Dx3TEg==",
+ "5l+RALcce+lTDnmXI+Wqqg==",
+ "pzJ4QmEBGRNiiX6z0xHh8g==",
+ "Vfl3YbqR6JRR7SIdsUA/vA==",
+ "cgfhOdB376a4GAcuACADvA==",
+ "inAefsQM6tiIhQCMtcPcyA==",
+ "FTSULGL8CMhmcc7Cyf/X8A==",
+ "9XSWpaZyHEy7V/tuw5uZEw==",
+ "+VtM1opKlgb/jrCwc4YjFA==",
+ "oF46xheuI/NUxUOnOttzvA==",
+ "Qy+lvhDbJCumr6kiPLd1oA==",
+ "swps7UEKpIbVBJ9SnPK3zQ==",
+ "b7wyIiJvJs+29QePxsdWtQ==",
+ "x3iDZxYyuHtG/9rNW5HMYg==",
+ "r1dx1g5UOksywvOaQTamfA==",
+ "KvVF3Si/fr4JQtr7jCJiog==",
+ "spvZ7hhtG5QY7JXs96lBUg==",
+ "ECL8mA5B6CswyDH6yJ4hVw==",
+ "7Uu+YsdS69dMSDYUr6vTag==",
+ "Rnm9pSvQRRbkHpOijraLZw==",
+ "aQJqpnXdzqNSFhMn3EJA2Q==",
+ "TctnXpd7Wd5ZXKMnOFHAQA==",
+ "+lPqG8l6mf2FWVGWflyF/g==",
+ "mPmnmL2oRRJmKYjQ6TfN3g==",
+ "fyXFcT5ZCawDBg74n1WSpg==",
+ "uq5Zrxq10pO1HoPxReT5og==",
+ "3eoCsOKXY8RDrHSdlXqmrA==",
+ "9nQv2BFG56xsHViN5UpHYw==",
+ "RtP/nJgy/ItyuDrpBbAotg==",
+ "5E/drRptfHmBhJ7qplujGg==",
+ "cUxyZvoqXbQ0a/0I9s6Zbg==",
+ "womzqSigwEF30V422YmxKw==",
+ "FPvZqDfN8dTFHLVOuYEbUA==",
+ "YZMXx+scKXp/v9GaJjb1bA==",
+ "bjURu5MRsNIZavG5HV0eZw==",
+ "iY0C9uSMEOn8ikT+J7+/Eg==",
+ "aXkD6BzsdkMEv7A+eYqQQQ==",
+ "dOcOfEDGHYG2kgmrglDkPw==",
+ "c7GjtY05Mh+cp6SNuWY3Ig==",
+ "lM1uY1oVncHXNzKs/cCEtQ==",
+ "7jXnQJkutLsi+r9aYmrMxw==",
+ "NgrugWWduj2qdWnEQf9dLA==",
+ "faYjmy/yn5iXdS28QCIdWw==",
+ "68XbaOvIZpCGb4G1gaKErA==",
+ "Yi67HkOLtGYXeL7WD4GPrA==",
+ "Puo8gXuUkwcoQViaXwkdSQ==",
+ "L202Et5aZh60Vl20LTKNFg==",
+ "4agAzQ5+dnTmLZEjsZs26g==",
+ "LegGM1ft8Y7Ka3CUxpObvg==",
+ "KRdILc1QDOpow5im/qY+Kw==",
+ "peMW+rpwmXrSwplVuB/gTA==",
+ "Pic1ncr+Zn6wv75zjAdzQA==",
+ "ilSPlWYbiPzIC13vQUBlOw==",
+ "GUlDufLoTalBqrG/h3mZ6w==",
+ "5twANNlT57T9BG4r2D9+Hw==",
+ "ENrnM8HlMi+5y8Hsu4Pn4A==",
+ "K/DzpLEbz1MpRjA6qyYn4Q==",
+ "yN1cHJRHDXoFxFZacL6wsw==",
+ "Rc6r+KqIePH+dnj1aNYCsQ==",
+ "8u/z5htgqXVU5Dqwd9whJQ==",
+ "jV575O42EYoqDNxCm9643Q==",
+ "xCxGo0h3lS8N6X+ivKfpjA==",
+ "us+2nfpj2gjI7s14Hw0gmA==",
+ "bp90A/rbESwVU7eh9xRTfQ==",
+ "5QtMXzbTafvKDQOWZP7M8w==",
+ "1gFCxPLjQlQGKmSGmHwmJQ==",
+ "m+/dnOIe6SaIFhfvg+ybDg==",
+ "9Dcg87+RPq9U+swRg4dH3Q==",
+ "mnjbL7WFmrWp0RUqS8AMGA==",
+ "/0e0E+NFmq8GeE5+y2Gekw==",
+ "y11mbpHHtka9Ep8cr2nEvQ==",
+ "GdmjRyliw+W21Q+dHO4CWA==",
+ "X65wWQTpkg756V/Nfn92kQ==",
+ "xj06KvacQOxRSofbhzBNgA==",
+ "nVDxVhaa2o38gd1XJgE3aw==",
+ "4IV+JOGXrltpkQamBRXMgA==",
+ "jIfp8LqaYXT88r/K3a8gNw==",
+ "vhT4dDtbMFVyevS6yCGy0g==",
+ "zMs7/x8hDt8xj2FFc5+6vA==",
+ "1J7u2N62JGb2VrnCRlJIrw==",
+ "3hJs9P/RRxB0CO4q0Icb+g==",
+ "ZpuVY1ZyoKD3hqosdsfT6Q==",
+ "6KIM7C7eWgxZtqZboiJvZQ==",
+ "vtb6fdqirkuUkqITAmXTlw==",
+ "C/rEVr22mw2u/1dwUx9VTg==",
+ "NrY4Q5C67haCWLK8HXHq9g==",
+ "X9qvEftCEFWX3gBU5hXy+Q==",
+ "0zgw7xNB3xVGaH48TyxaNQ==",
+ "g7J9Jy/PJrAGRgVdvA+bEg==",
+ "9zb+anAyZVBzuU9rW4cJtg==",
+ "6Zc5FzT/m0YIjxEPYA6zDQ==",
+ "R2YPNlvCbVK0EodTR7czIw==",
+ "gsI6EGgXMtDu+1u364A8mw==",
+ "Bg2wBFb1/xaxeEiHfBHX+A==",
+ "64aapfVI6dV3LpTK56KZlg==",
+ "HdgcJU0W3yVnH69VYStmug==",
+ "qTDCcv+LK3JPFB/++t66IQ==",
+ "P0HEIXMnAmbvq+QYREwFzw==",
+ "aaU7CAmtyE35jNKTkyXOkg==",
+ "r9G97WKDiQ48qJHP9LBRNg==",
+ "8mPgQhYVDn8KshDDvvf5SA==",
+ "GCQiiOLDguXLiYwuLcFPsA==",
+ "R2Use39If2C0FVBP7KDerA==",
+ "23C4eh3yBb5n/RNZeTyJkA==",
+ "2QQtKtBAm2AjJ5c0WQ6BQA==",
+ "Qc+XYy2qyWJ5VVwd2PExbw==",
+ "zJ7ScHNxr2leCDNNcuDApA==",
+ "vFtC0B2oe1gck28JOM1dyg==",
+ "bLEntCrCHFy9pg3T3gbBzg==",
+ "G3PmmPGHaWHpPW30xQgm3Q==",
+ "me61ST+JrXM5k3/a11gRAA==",
+ "+LJYVZl1iPrdMU3L5+nxZw==",
+ "CLPzjXKGGpJ0VrkSJp7wPQ==",
+ "Pc+u0MAzp4lndTz4m6oQ5w==",
+ "cwBNvZc0u4bGABo88YUsVQ==",
+ "q7m/EtZySBjZNBjQ5m1hKw==",
+ "8ZBiwr842ZMKphlqmNngHw==",
+ "LMCZqd3UoF/kHHwzTdj7Tw==",
+ "0ODJyWKJSfObo+FNdRQkkA==",
+ "ViweSJuNWbx5Lc49ETEs/A==",
+ "x+8rwkqKCv0juoT5m1A4eg==",
+ "pxuSWn1u+bHtRjyh2Z8veA==",
+ "GKzs8mlnQQc58CyOBTlfIg==",
+ "Owg8qCpjZa+PmbhZew6/sw==",
+ "YLz+HA6qIneP+4naavq44Q==",
+ "9ajIS45NTicqRANzRhDWFA==",
+ "DjeSrUoWW2QAZOAybeLGJg==",
+ "qxALQrqHoDq9d91nU0DckA==",
+ "yPIeWcW8+3HjDagegrN8bw==",
+ "ocpLRASvTgqfkY20YlVFHQ==",
+ "RuLeQHP1wHsxhdmYMcgtrQ==",
+ "3WwITQML938W9+MUM56a3A==",
+ "ZbLVNTQSVZQWTNgC4ZGfQg==",
+ "X6Ln4si8G5aKar52ZH/FEQ==",
+ "+gbitI/gpxebN/rK7qj8Fw==",
+ "7cnUHeaPO8txZGGWHL9tKg==",
+ "epY+dsm5EMoXnZCnO4WSHw==",
+ "nf8x+F03kOpMhsCSUWEhVg==",
+ "VE4sLM5bKlLdk85sslxiLQ==",
+ "Hs3vUOOs2TWQdQZHs+FaQQ==",
+ "hkOBNoHbno2iNR7t3/d4vg==",
+ "Ar9N1VYgE7riwmcrM3bA2Q==",
+ "SbMjjI8/P8B9a9H2G0wHEQ==",
+ "tU31r8zla146sqczdKXufg==",
+ "tFmWYH82I3zb+ymk5dhepA==",
+ "XHjrTLXkm/bBY/BewmJcCQ==",
+ "FV/D5uSco+Iz8L+5t7E8SA==",
+ "yKLLiqzxfrCsr6+Rm6kx1Q==",
+ "B6reUwMkQFaCHb9BYZExpw==",
+ "5jyuDp82Fux+B0+zlx8EXw==",
+ "WGKFTWJac8uehn3N59yHJw==",
+ "JQf9UmutPh3tAnu7FDk3nA==",
+ "hv5GrLEIjPb4bGOi8RSO0w==",
+ "p3V7NfveB6cNxFW7+XQNeQ==",
+ "DinJuuBX9OKsK5fUtcaTcQ==",
+ "UEMwF4kwgIGxGT4jrBhMPQ==",
+ "Y78dviyBS3Jq9zoRD5sZtQ==",
+ "zbjXhZaeyMfdTb2zxvmRMg==",
+ "kydoXVaNcx1peR5g6i588g==",
+ "M2suCoFHJ5fh9oKEpUG3xA==",
+ "/VnKh/NDv7y/bfO6CWsLaQ==",
+ "S+b37XhKRm8cDwRb1gSsKQ==",
+ "jz7QlwxCIzysP39Cgro8jg==",
+ "IjmLaf3stWDAwvjzNbJpQA==",
+ "cHSj5dpQ04h/WyefjABfmQ==",
+ "+gO0bg8LY+py2dLM1sM7Ag==",
+ "fSANOaHD0Koaqg7AoieY9A==",
+ "vqYHQ3MnHrAIAr1QHwfIag==",
+ "Uh1mvZNGehK1AaI4a1auKQ==",
+ "HCbHUfsTDl6+bxPjT57lrA==",
+ "S7Vjy/gOWp0HozPP1RUOZw==",
+ "KPh6TwYpspne4KZA6NyMbw==",
+ "cfh5VZFmIqJH/bKboDvtlA==",
+ "H1zH9I8RwfEy5DGz3z+dHw==",
+ "2ksediOVrh4asSBxKcudTg==",
+ "+jVN/3ASc2O44sX6ab8/cg==",
+ "uvKYnKE01D5r7kR9UQyo5A==",
+ "BB9PTlwKAWkExt3kKC/Wog==",
+ "yqQPU4jT9XvRABZgNQXjgg==",
+ "6v3eTZtPYBfKFSjfOo2UaA==",
+ "49z/15Nx9Og7dN9ebVqIzg==",
+ "VjclDY8HN4fSpB263jsEiQ==",
+ "vSKsa0JhLCe9QFZKkcj58Q==",
+ "PolhKCedOsplEcaX4hQ0YQ==",
+ "D0Qt9sRlMaPnOv1xaq+XUg==",
+ "gBgJF0PiGEfcUnXF0RO7/w==",
+ "sC11Rf/mau3FG5SnON4+vQ==",
+ "rKb3TBM4EPx/RErFOFVCnQ==",
+ "+n0K7OB2ItzhySZ4rhUrMg==",
+ "Epm0d/DvXkOFeM4hoPCBrg==",
+ "K8PVQhEJCEH1ghwOdztjRw==",
+ "xjA21QjNdThLW3VV7SCnrg==",
+ "nE72uQToQFVLOzcu/nMjww==",
+ "2Hc5oyl0AYRy2VzcDKy+VA==",
+ "Y7XpxIwsGK3Lm/7jX/rRmg==",
+ "MK7AqlJIGqK2+K5mCvMXRQ==",
+ "mXycPfF5zOvcj1p4hnikWw==",
+ "V1fvtnJ0L3sluj9nI5KzRw==",
+ "TahqPgS7kEg+y6Df0HBASw==",
+ "EKU3OVlT4b/8j3MTBqpMNg==",
+ "EdvIAKdRAXj7e42mMlFOGQ==",
+ "uPm+cF4Jq08S5pQhYFjU8A==",
+ "CnIwpRVC2URVfoiymnsdYQ==",
+ "wyx5mnUMgP5wjykjAfTO7w==",
+ "OwIGvTh8FPFqa4ijNkguAw==",
+ "4ID0PHTzIMZz2rQqDGBVfA==",
+ "rlXt6zKE7DswUl0oWGOQUQ==",
+ "4NP8EFFJyPcuQKnBSxzKgQ==",
+ "bJgsuw29cO2WozqsGZxl7w==",
+ "b3q8kjHJPj9DWrz3yNgwjQ==",
+ "QGYFMpkv37CS2wmyp42ppg==",
+ "Kzs+/IZJO8v4uIv9mlyJ2Q==",
+ "ZJY+hujfd58mTKTdsmHoQQ==",
+ "R8FxgXWKBpEVbnl41+tWEw==",
+ "+CvLiih/gf2ugXAF+LgWqw==",
+ "BDbfe/xa9Mz1lVD82ZYRGA==",
+ "Dz90OhYEjpaJ/pxwg1Qxhg==",
+ "MLHt6Ak288G0RGhCVaOeqA==",
+ "r0QffVKB9OD9yGsOtqzlhA==",
+ "hK8KhTFcR06onlIJjTji/Q==",
+ "wMum67lfk5E1ohUObJgrOg==",
+ "JKmZqz9cUnj6eTsWnFaB0A==",
+ "rtJdfki8fG6CB36CADp0QA==",
+ "cUyqCa7Oue934riyC17F8g==",
+ "y4Y4mSSTw/WrIdRpktc5Hw==",
+ "r36kVMpF+9J+sfI3GeGqow==",
+ "ydVj2odhergi+2zGUwK4/A==",
+ "J2NFyb8cXEpZyxWDthYQiA==",
+ "qYuo5vY8V3tZx41Kh9/4Dw==",
+ "jrfRznO0nAz6tZM1mHOKIA==",
+ "JSr/lqDej81xqUvd/O2s7w==",
+ "vHGjRRSlZHJIliCwIkCAmQ==",
+ "sQAxqWXeiu/Su0pnnXgI9A==",
+ "xPe76nHyHmald6kmMQsKdg==",
+ "50jASqzGm4VyHJbFv8qVRA==",
+ "uuiJ+yB7JLDh2ulthM0mjg==",
+ "TI90EuS/bHq/CAlX32UFXg==",
+ "JgxNrUlL8wutG04ogKFPvw==",
+ "aMa1yVA71/w6Uf1Szc9rMA==",
+ "k/Aou2Jmyh8Bu3k8/+ndsQ==",
+ "iANKiuMqWzrHSk9nbPe3bQ==",
+ "7GgNLBppgAKcgJCDSsRqOQ==",
+ "bzVeU2qM9zHuzf7cVIsSZw==",
+ "rkeLYwMZ1/pW2EmIibALfA==",
+ "91+Yms6Oy/rP0rVjha5z9w==",
+ "JgXSPXDqaS1G9NqmJXZG0A==",
+ "ZzduJxTnXLD9EPKMn1LI4Q==",
+ "6W79FmpUN1ByNtv5IEXY4w==",
+ "Y1Nm3omeWX2MXaCjDDYnWQ==",
+ "ejfikwrSPMqEHjZAk3DMkA==",
+ "WNfDNaWUOqABQ6c6kR+eyw==",
+ "4BkqgraeXY7yaI1FE07Evw==",
+ "AjHz9GkRTFPjrqBokCDzFw==",
+ "T/6gSz2HwWJDFIVrmcm8Ug==",
+ "VWy9lB5t4fNCp4O/4n8S4w==",
+ "/FdZzSprPnNDPwbhV1C0Cg==",
+ "LUWxfy4lfgB5wUrqCOUisw==",
+ "r1VGXWeqGeGbfKjigaAS+Q==",
+ "ztULoqHvCOE6qV7ocqa4/w==",
+ "QCpzCTReHxGm5lcLsgwPCA==",
+ "Hst3yfyTB7yBUinvVzYROQ==",
+ "gf1Ypna/Tt+TZ08Y+GcvGg==",
+ "3rbml1D0gfXnwOs5jRZ3gA==",
+ "2vm7g3rk1ACJOTCXkLB3zA==",
+ "11FE2kknwYi2Qu0JUKMn3A==",
+ "1b2uf+CdVjufqiVpUShvHw==",
+ "0a4SafpDIe8V4FlFWYkMHw==",
+ "7btpMFgeGkUsiTtsmNxGQA==",
+ "dUx1REyXKiDFAABooqrKEA==",
+ "knYKU74onR6NkGVjQLezZg==",
+ "Scto+9TWxj1eZgvNKo+a9A==",
+ "cvZT1pvNbIL8TWg+SoTZdA==",
+ "1nXByug2eKq0kR3H3VjnWQ==",
+ "tG+rpfJBXlyGXxTmkceiKA==",
+ "7W9aF7dxnL+E8lbS/F7brg==",
+ "8vr+ERVrM99dp+IGnCWDGQ==",
+ "oFNMOKbQXcydxnp8fUNOHw==",
+ "uJZGw3IY2nCcdVeWW1geNQ==",
+ "q6LG0VzO1oxiogAAU63hyg==",
+ "f0H/AFSx2KLZi9kVx5BAZg==",
+ "1RQZ2pWSxT+RKyhBigtSFg==",
+ "scCQPl0em2Zmv/RQYar60g==",
+ "A2ODff+ImIkreJtDPUVrlg==",
+ "vRgkZZGVN7YZrlml0vxrKA==",
+ "68jPYo3znYoU4uWI7FH3/g==",
+ "iJ2nT8w8LuK11IXYqBK+YA==",
+ "54XELlPm8gBvx8D5bN3aUg==",
+ "PTAm/jGkie7OlgVOvPKpaA==",
+ "v7BrkRmK0FfWSHunTRHQFQ==",
+ "dVh/XMTUIx1nYN4q1iH1bA==",
+ "TSGL3iQYUgVg/O9SBKP9EA==",
+ "wTO49YX/ePHMWtcoxUAHpw==",
+ "bMb1ia0rElr2ZpZVhva0Jw==",
+ "sNmW2b2Ud7dZi3qOF8O8EQ==",
+ "3djRJvkZk9O2bZeUTe+7xQ==",
+ "I9KNZC1tijiG1T72C4cVqQ==",
+ "sQzCwNDlRsSH7iB9cTbBcg==",
+ "mk1CKDah7EzDJEdhL22B7w==",
+ "lON3WM0uMJ30F8poBMvAjQ==",
+ "88PNi9+yn3Bp4/upgxtWGA==",
+ "C+Ssp+v1r+00+qiTy2d7kA==",
+ "11U5XEwfMI7avx014LfC8g==",
+ "xsf0m31Am0W9eLhopAkfnA==",
+ "d13Rj3NJdcat0K/kxlHLFw==",
+ "UP7NXAE0uxHRXUAWPhto0w==",
+ "ZKXxq9yr7NGBOHidht34uQ==",
+ "Fd2fYFs8vtjws2kx1gf6Rw==",
+ "ojf6uL85EuEYgLvHoGhUrw==",
+ "KjnL3x+56r3M2pDj1pPihA==",
+ "WdCWezJU4JK43EOZ9YHVdg==",
+ "/jH6imhTPZ/tHI4gYz2+HA==",
+ "+OLntmlsMBBYPREPnS6iVw==",
+ "5lfLJAk1L3QzGMML3fOuSw==",
+ "AZs3v4KJYxdi8T1gjVjI2Q==",
+ "7pkUY2UzSbGnwLvyRrbxfA==",
+ "BjfOelfc1IBgmUxMJFjlbQ==",
+ "TcGhAJHRr7eMwGeFgpFBhg==",
+ "Y7iDCWYrO1coopM3RZWIPg==",
+ "mnalaO6xJucSiZ0+99r3Cg==",
+ "plXHHzA8X9QGwWzlJxhLRw==",
+ "Zqd6+81TwYuiIgLrToFOTQ==",
+ "1Pmnur6TbZ9cmemvu0+dSA==",
+ "OaNpzwshdHUZMphQXa6i8w==",
+ "WKehT4nGF2T7aKuzABDMlA==",
+ "4LvQSicqsgxQFWauqlcEjw==",
+ "BMZB1FwvAuEqyrd0rZrEzw==",
+ "YfbfE3WyYOW7083Y8sGfwQ==",
+ "46FCwqh+eMkf+czjhjworw==",
+ "734u4Y1R3u7UNUnD+wWUoA==",
+ "yf06Slv9l3IZEjVqvxP2aA==",
+ "bIk7Fa6SW7X18hfDjTKowg==",
+ "DnF6TYSJxlc+cwdfevLYng==",
+ "ionqS0piAOY2LeSReAz4zg==",
+ "hlMumZ7RJFpILuKs09ABtw==",
+ "NjeDgQ1nzH1XGRnLNqCmSg==",
+ "o7y4zQXQAryST2cak4gVbw==",
+ "29EybnMEO95Ng4l/qK4NWQ==",
+ "udU65VtsvJspYmamiOsgXw==",
+ "v1AWe5qb5y3vSKFb7ADeEw==",
+ "wK6Srd83eLigZ11Q20XGrg==",
+ "GmC+0rNDMIR+YbUudoNUXw==",
+ "W4utAK3ws0zjiba/3i91YA==",
+ "MlKWxeEh8404vXenBLq4bw==",
+ "Gdf4VEDLBrKJNQ8qzDsIyw==",
+ "Z9bDWIgcq6XwMoU2ECDR5Q==",
+ "VIkS30v268x+M1GCcq/A8A==",
+ "iPwX3SbbG9ez9HoHsrHbKw==",
+ "yKrsKX4/1B1C0TyvciNz5w==",
+ "BophnnMszW5o+ywgb+3Qbw==",
+ "eJLrGwPRa6NgWiOrw1pA7w==",
+ "eV+RwWPiGEB+76bqvw+hbA==",
+ "oad5SwflzN0vfNcyEyF4EA==",
+ "Uw6Iw+TP9ZdZGm2b/DAmkg==",
+ "9qWLbRLXWIBJUXYjYhY2pg==",
+ "dxWv00FN/2Cgmgq9U3NVDQ==",
+ "AX1HxQKXD12Yv5HWi39aPQ==",
+ "J0NauydfKsACUUEpMhQg8A==",
+ "mxug34EekabLz0JynutfBg==",
+ "bNq/hj0Cjt4lkLQeVxDVdQ==",
+ "nW3zZshjZEoM8KVJoVfnuQ==",
+ "ghp8sWGKWw20S/z1tbTxFg==",
+ "S4rFuiKLFKZ+cL7ldiTwpg==",
+ "8ZqmPJDnQSOFXvNMRQYG2Q==",
+ "6XYqR2WvDzx4fWO7BIOTjA==",
+ "Uo+FIhw1mfjF6/M8cE1c/Q==",
+ "bsHIShcLS134C+dTxFQHyA==",
+ "19yQHaBemtlgo2QkU5M6jQ==",
+ "sWLcS+m4aWk31BiBF+vfJQ==",
+ "BlCgDd7EYDIqnoAiKOXX6Q==",
+ "MrxR3cJaDHp0t3jQNThEyg==",
+ "cMo6l1EQESx1rIo+R4Vogg==",
+ "VOvrzqiZ1EHw+ZzzTWtpsw==",
+ "1/ZheMsbojazxt31j/l3iA==",
+ "0QxPAqRF8inBuFEEzNmLjA==",
+ "UXUNYEOffgW3AdBs7zTMFA==",
+ "lOPJhHqCtMRFZfWMX/vFZQ==",
+ "rXSbbRABEf4Ymtda45w8Fw==",
+ "jfegbZSZWkDoPulFomVntA==",
+ "hfcH5Az2M7rp+EjtVpPwsg==",
+ "VsXEBIaMkVftkxt1kIh7TA==",
+ "M20iX2sUfw5SXaZLZYlTaA==",
+ "VUDsc9RMS1fSM43c+Jo9dQ==",
+ "itPtn+JaO4i7wz2wOPOmDQ==",
+ "rCxoo4TP/+fupXMuIM0sDA==",
+ "cSHSg9xJz/3F6kc+hKXkwg==",
+ "b4BoZmzVErvuynxirLxn0w==",
+ "e4B3HmWjW+6hQzcOLru6Xg==",
+ "lTE6u9G/RzvmbuAzq2J2/Q==",
+ "897ptlztTjr7yk+pk8MT0Q==",
+ "jd6IpPJwOJW1otHKtKZ5Gw==",
+ "b4aFwwcWMXsSdgS1AdFOXA==",
+ "FltEN+7NKvzt+XAktHpfHA==",
+ "ZyDh3vCQWzS5DI1zSasXWA==",
+ "kcJ1acgBv6FtUhV8KuWoow==",
+ "zgEyxj/sCs63O98sZS94Yw==",
+ "/kGxvyEokQsVz0xlKzCn2A==",
+ "cxqHS4UbPolcYUwMMzgoOA==",
+ "62RHCbpGU8Hb+Ubn+SCTBg==",
+ "ePlsM/iOMme2jEUYwi15ng==",
+ "0fN+eHlbRS6mVZBbH/B9FQ==",
+ "k0XIjxp2vFG7sTrKcfAihA==",
+ "0rfG4gRugAwVP0i3AGVxxg==",
+ "M98hjSxCwvZ27aBaJTGozQ==",
+ "kzGNkWh3fz27cZer4BspUQ==",
+ "3CJbrUdW68E3Drhe4ahUnQ==",
+ "NGApiVkDSwzO45GT57GDQw==",
+ "lMjip5hbCjkD9JQjuhewDg==",
+ "GrSbnecYAC3j5gtoKntL0A==",
+ "9dbn0Kzwr9adCEfBJh78uQ==",
+ "64QzHOYX0A9++FqRzZRHlQ==",
+ "YZt6HwCvdI5DRQqndA/hBQ==",
+ "6GXHGF62/+jZ7PfIBlMxZw==",
+ "PBULPuFXb6V3Di713n3Gug==",
+ "8Cm19vJW8ivhFPy0oQXVNA==",
+ "zDSQ3NJuUGkVOlvVCATRwA==",
+ "6QAtjOK9enNLRhcVa2iaTg==",
+ "v/PshI6JjkL9nojLlMNfhg==",
+ "yTgN5xFIdz1MzFS6xMl5uQ==",
+ "SCO9nQncEcyVXGCtx30Jdg==",
+ "7b0oo4+qphu6HRvJq6qkHQ==",
+ "ol9xhVTG9e1wNo50JdZbOA==",
+ "hIABph+vhtSF5kkZQtOCTA==",
+ "k+IBS52XdOe5/hLp28ufnA==",
+ "6HnWgYNKohqhoa1tnjjU3A==",
+ "HDxGhvdQwGh0aLRYEGFqnw==",
+ "LDuBcL5r3PUuzKKZ9x6Kfw==",
+ "HPvYV94ufwiNHEImu4OYvQ==",
+ "h2cnQQF2/R3Mq2hWdDdrTg==",
+ "nqpKfidczdgrNaAyPi7BOQ==",
+ "2ywo4t5PPSVUCWDwUlOVwQ==",
+ "jZMDIu95ITTjaUX0pk4V5g==",
+ "bA2kaTpeXflTElTnQRp6GQ==",
+ "lwYQm2ynA3ik2gE1m11IEg==",
+ "5ugVOraop5P5z5XLlYPJyQ==",
+ "l2NppPcweAtmA1V2CNdk2Q==",
+ "DbWQI3H2tcJsVJThszfHGA==",
+ "H6HPFAcdHFbQUNrYnB74dA==",
+ "H1NJEI+fvOQbI51kaNQQjQ==",
+ "53UccFNzMi9mKmdeD82vAw==",
+ "lffapwUUgaQOIqLz2QPbAg==",
+ "rSvhrHyIlnIBlfNJqemEbw==",
+ "BLJk9wA88z6e0IQNrWJIVw==",
+ "5m1ijXEW+4RTNGZsDA/rxQ==",
+ "GG8a3BlwGrYIwZH9j3cnPA==",
+ "HhBHt5lQauNl7EZXpsDHJA==",
+ "/XjB6c5fxFGcKVAQ4o+OMw==",
+ "+tuUmnRDRWVLA+1k0dcUvg==",
+ "SM7E98MyViSSS9G0Pwzwyw==",
+ "c5q/8n7Oeffv3B1snHM/lA==",
+ "kwlAQhR2jPMmfLTAwcmoxw==",
+ "0b/xj6fd0x+aB8EB0LC4SA==",
+ "S8jlvuYuankCnvIvMVMzmg==",
+ "kZkmDatUOdIqs7GzH3nI1A==",
+ "obW3kzv2KBvuckU7F+tfjA==",
+ "pa8nkpAAzDKUldWjIvYMYg==",
+ "m+eh+ZqS74w2q0vejBkjaw==",
+ "LcoJBEPTlSsQwfuoKQUxEw==",
+ "KO2XVYyNZadcQv8aCNn5JA==",
+ "uvzmRcvgepW6mZbMfYgcNw==",
+ "KhUT2buOXavGCpcDOcbOYg==",
+ "fo3JL+2kPgDWfP+CCrFlFw==",
+ "wIfvvLKC61gOpsddUFjVog==",
+ "SPHU6ES1WVm0Mu2LB+YjrA==",
+ "LWWfRqgtph1XrpxF4N64TA==",
+ "LCvz/h9hbouXCmdWDPGWqg==",
+ "PXC6ZpdMH0ATis/jGW12iA==",
+ "z920R8eahJPiTsifrPYdxA==",
+ "GIHKW6plyLra0BmMOurFgA==",
+ "k6OmSlaSZ5CB0i7SD9LczQ==",
+ "YZ39RIXpeLAhyMgmW2vfkQ==",
+ "bs2QG8yYWxPzhtyMqO6u3A==",
+ "pKaTI+TfcV3p/sxbd2e7YQ==",
+ "xWYecfzAtXT9WyQ8NYY/hw==",
+ "Fz8EI+ZpYlbcttSHs5PfpA==",
+ "wfwuxn+Vja1DNwiDwL2pcQ==",
+ "wux5Y8AipBnc5tJapTzgEQ==",
+ "U+oTpcjhc0E+6UjP11OE/Q==",
+ "yTVJKBn72RjakMBXDoBKHg==",
+ "0TxcYwG72dT7Tg+eG8pP1w==",
+ "imZ+mwiT22sW2M9alcUFfg==",
+ "CkDIoAFLlIRXra78bxT/ZA==",
+ "4qMSNAxichi3ori/pR+o0w==",
+ "zNLlWGW/aKBhUwQZ4DZWoQ==",
+ "D31ZticrjGWAO45l5hFh7A==",
+ "HdXg64DBy5WcL5fRRiUVOg==",
+ "yhI5jHlfFJxu4eV5VJO2zQ==",
+ "e9GqAEnk8XI5ix6kJuieNQ==",
+ "EC0+iUdSZvmIEzipXgj7Gg==",
+ "chwv4+xbEAa93PHg8q9zgQ==",
+ "B1VVUbl8pU0Phyl1RYrmBg==",
+ "A+DLpIlYyCb9DaarpLN76g==",
+ "wHA+D5cObfV3kGORCdEknw==",
+ "+Mp+JIyO0XC5urvMyi3wvQ==",
+ "vUE8Iw3NyWXURpXyoNJdaw==",
+ "ParhxI6RtLETBSwB0vwChQ==",
+ "NxSdT2+MUkQN49pyNO2bJw==",
+ "JSyhTcHLTfzHsPrxJyiVrA==",
+ "PAlx9+U+yQCAc5Fi0BOG0w==",
+ "W/0s1x3Qm+wN8DhROk6FrQ==",
+ "L3Jt5dHQpWQk74IAuDOL8g==",
+ "VWb8U4jF/Ic0+wpoXi/y/g==",
+ "1wBuHqS1ciup31WTfm3NPg==",
+ "BDNM1u/9mefjuW1YM2DuBg==",
+ "SDi5+FoP9bMyKYp+vVv1XA==",
+ "23d9B9Gz5kUOi1I//EYsSQ==",
+ "/a9O7kWeXa0le45ab3+nVw==",
+ "PcoVtZrS1x1Q+6nfm4f80w==",
+ "A6TLWhipfymkjPYq8kaoDQ==",
+ "lzUQ1o7JAbdJYpmEqi6KnQ==",
+ "/2jGyMekNu7U136K+2N3Jg==",
+ "ZItMIn1vhGqAlpDHclg0Ig==",
+ "Ee4A3lTMLQ7iDQ7b8QP8Qg==",
+ "bO55S58bqDiRWXSAIUGJKw==",
+ "zeHF6fdeqcOId3fRUGscRw==",
+ "BxsDnI8jXr4lBwDbyHaYXw==",
+ "ylA6sU7Kaf9fMNIx1+sIlw==",
+ "ZWXfE3uGU91WpPMGyknmqw==",
+ "f1+fHgR5rDPsCZOzqrHM7Q==",
+ "8VqeoQELbCs232+Mu+HblA==",
+ "beSrliUu0BOadCWmx+yZyA==",
+ "NQVQfN3nIg9ipHiFh4BvfQ==",
+ "4wnUAbPT3AHRJrPwTTEjyw==",
+ "/cdR1i5TuQvO+u3Ov3b0KQ==",
+ "wtyAZIfhomcHe9dLbYoSvA==",
+ "ulpDxLeQnIRPnq6oaah2AA==",
+ "pdPwUHauXOowaq9hpL2yFw==",
+ "1+A9FCGP3bZhk6gU3LQtNg==",
+ "raYifKqev8pASjjuV+UTKQ==",
+ "+OERSmo7OQUUjudkccSMOA==",
+ "FeRovookFQIsXmHXUJhGOw==",
+ "USCvrMEm/Wqeu9oX6FrgcQ==",
+ "kly/2kE4/7ffbO34WTgoGg==",
+ "IindlAnepkazs5DssBCPhA==",
+ "Bq82MoMcDjIo/exqd/6UoA==",
+ "ocvA1/NbyxM0hanwwY6EiA==",
+ "rtd6mqFgGe98mqO0pFGbSw==",
+ "nvLEpj6ZZF3LWH3wUB6lKg==",
+ "AGd0rcLnQ0n+meYyJur1Pw==",
+ "wI7JrSPQwYHpv2lRsQu9nQ==",
+ "OnmvXbyT2BYsSDJYZhLScA==",
+ "CmBf5qchS1V3C2mS6Rl4bw==",
+ "TafM7nTE5d+tBpRCsb8TjQ==",
+ "wxkb8evGEaGf/rg/1XUWiA==",
+ "y1J+o6DC2sETFsySgpDZyA==",
+ "SVLHWPCCH7GPVCF7QApPbw==",
+ "HMWOlMmzocOIiJ7yG1YaDQ==",
+ "DJmrmNRKARzsTCKSMLmcNA==",
+ "/XC/FmMIOdhMTPqmy4DfUA==",
+ "63OTPaKM0xCfJOy9EDto+Q==",
+ "PxReytUUn/BbxYTFMu1r2Q==",
+ "WjDqf1LyFyhdd8qkwWk+MA==",
+ "/DiUApY7cVp5W9o24rkgRA==",
+ "alJtvTAD7dH/zss/Ek1DMQ==",
+ "xLm/bJBonpTs0PwsF0DvRg==",
+ "eAOEgF5N80A/oDVnlZYRAw==",
+ "LqgzKxbI6WTMz0AMIDJR5w==",
+ "MJ1FuK8PXcmnBAG9meU84A==",
+ "JLq/DrW2f26NaRwfpDXIEA==",
+ "fsrX00onlGvfsuiCc35pGg==",
+ "tXVb5f90k9l3e1oK2NGXog==",
+ "1JRgSHnfAQFQtSkFTttkqQ==",
+ "B0TaUQ6dKhPfSc5V/MjLEQ==",
+ "nkbLVLvh3ClKED97+nH+7Q==",
+ "avFTp3rS6z5zxQUZQuaBHQ==",
+ "lNF8PvUIN02NattcGi5u4g==",
+ "bBEndaOStXBpAK79FrgHaw==",
+ "dM9up4vKQV5LeX82j//1jQ==",
+ "4WO6eT0Rh6sokb29zSJQnQ==",
+ "RHKCMAqrPjvUYt13BVcmvw==",
+ "Ju4YwtPw+MKzpbC0wJsZow==",
+ "tzV7ixFH37ze4zuLILTlfA==",
+ "oPlhC4ebXdkIDazeMSn1fQ==",
+ "5pje7qyz8BRsa8U4a4rmoA==",
+ "7E6V6/zSjbtqraG7Umj+Jw==",
+ "8QK7emHS6rAcAF5QQemW/A==",
+ "LhqRc9oewY4XaaXTcnXIHQ==",
+ "p/7qM5+Lwzw1/lIPY91YxQ==",
+ "fy54Milpa7KZH/zgrDmMXQ==",
+ "LyPXOoOPMieqINtX8C9Zag==",
+ "aD4QvtMlr8Lk/zZgZ6zIMg==",
+ "dsueq9eygFXILDC7ZpamuA==",
+ "+mJLK+6qq8xFv7O/mbILTw==",
+ "nHUpYmfV59fe3RWaXhPs3Q==",
+ "VbCoGr8apEcN7xfdaVwVXw==",
+ "/2Chaw2M9DzsadFFkCu6WQ==",
+ "rKAQxu80Q8g1EEhW5Wh8tg==",
+ "RJJqFMeiCZHdsqs72J17MQ==",
+ "GF2yvI9UWf1WY7V7HXmKPA==",
+ "JyIDGL1m/w+pQDOyyeYupA==",
+ "wR2Gxb07nkaPcZHlEjr8iA==",
+ "PbDVq2Iw1eeM8c2o/XYdTA==",
+ "BL3buzSCV78rCXNEhUhuKQ==",
+ "i42XumprV/aDT5R0HcmfIQ==",
+ "DuEKxykezAvyaFO2/5ZmKQ==",
+ "6ACvJNfryPSjGOK39ov8Qg==",
+ "YaUKOTyByjUvp1XaoLiW5Q==",
+ "jNcMS2zX1iSZN9uYnb2EIg==",
+ "VRnx+kd6VdxChwsfbo1oeQ==",
+ "4Qinl7cWmVeLJgah8bcNkw==",
+ "Fiy3hkcGZQjNKSQP9vRqyA==",
+ "HaSc7MZphCMysTy2JbTJkw==",
+ "VhYGC8KYe5Up+UJ2OTLKUw==",
+ "K2gk9zWGd0lJFRMQ1AjQ/Q==",
+ "NfxVYc3RNWZwzh2RmfXpiA==",
+ "JGeqHRQpf4No74aCs+YTfA==",
+ "7VHlLw20dWck+I8tCEZilA==",
+ "V5HKdaTHjA8IzvHNd9C51g==",
+ "9TalxEyFgy6hFCM73hgb7Q==",
+ "R/y6+JJP8rzz1KITJ4qWBw==",
+ "7bM/pn4G7g7Zl6Xf1r62Lg==",
+ "CHsFJfsvZkPWDXkA6ZMsDQ==",
+ "uXuPA/2KJbb7ZX+NymN3dw==",
+ "o+nYS4TqJc6XOiuUzEpC3A==",
+ "8N3mhHt29FZDHn1P2WH1wQ==",
+ "uZ2gUA74/7Q33tI2TcGQlg==",
+ "8B12CamjOGzJDnQ+RkUf4w==",
+ "9FdpxlIFu11qIPdO7WC5nw==",
+ "G+sGF13VXPH4Ih6XgFEXxg==",
+ "y+1I05LDAYJ09tKMs3zW6g==",
+ "gnkadeCgjdmLdlu/AjBZJg==",
+ "1I+UVx3krrD4NhzO7dgfHQ==",
+ "8LNNoHe6rEQyJ0ebl151Mw==",
+ "yOE90OHQdyOfrAgwDvn2gA==",
+ "ayBGGPEy++biljvGcwIjXA==",
+ "o/Y4U6rWfsUCXJ72p5CUGw==",
+ "5kvyy902llnYGQdn2Py04w==",
+ "6k2cuk0McTThSMW/QRHfjA==",
+ "2XrR2hjDEvx8MQpHk9dnjw==",
+ "fv/PW8oexJYWf5De30fdLQ==",
+ "861mBNvjIkVgkBiocCUj/Q==",
+ "NKGY0ANVZ0gnUtzVx1pKSw==",
+ "4DIPP/yWRgRuFqVeqIyxMQ==",
+ "cgSEbLqqvDsNUyeA3ryJ6Q==",
+ "xbBxUP9JyY0wDgHDipBHeg==",
+ "c3WVxyC5ZFtzGeQlH5Gw+w==",
+ "ZKeTDCboOgCptrjSfgu0xw==",
+ "DjHszpS8Dgocv3oQkW/VZQ==",
+ "Iqszlv4R49UevjGxIPMhIA==",
+ "uChFnF0oCwARhAOz/d47eA==",
+ "0egBaMnAf0CQEXf1pCIKnA==",
+ "FnVNxl5AFH1AieYru2ZG+A==",
+ "2Ct+pLXrK6Ku1f4qehjurQ==",
+ "x2nSgcTjA3oGgI8mMgiqjw==",
+ "AUGmvZkpkKBry5bHZn4DJA==",
+ "x8kRVzohTdhkryvYeMvkMw==",
+ "rXfWkabSPN+23Ei1bdxfmQ==",
+ "ElTNyMR4Rg8ApKrPw88WPg==",
+ "9jxA/t3TQx8dQ+FBsn/YCg==",
+ "I07W2eDQwe6DVsm1zHKM8A==",
+ "0p1jMr06OyBoXQuSLYN4aQ==",
+ "odGhKtO4bDW5R8SYiI5yCg==",
+ "5Q/Y2V0iSVTK8HE8JerEig==",
+ "Ily2MKoFI1zr5LxBy93EmQ==",
+ "8dUcSkd2qnX5lD9B+fUe+Q==",
+ "80UE+Ivby3nwplO/HA7cPw==",
+ "sS6QcitMPdvUBLiMXkWQkw==",
+ "5VY++KiWgo7jXSdFJsPN3A==",
+ "aY6B28XdPnuYnbOy9uSP8A==",
+ "ZfRlID+pC1Rr4IY14jolMw==",
+ "/YuQw7oAF08KDptxJEBS9g==",
+ "16d+fhFlgayu3ttKVV/pbg==",
+ "8dBIsHMEAk7aoArLZKDZtg==",
+ "wRqaDZVHHurp5whOQ1kDbQ==",
+ "lFUq6PGk9dBRtUuiEW7Cug==",
+ "FoJZ61VrU8i084pAuoWhDQ==",
+ "4mig4AMLUw+T/ect9p4CfA==",
+ "Po0lhBfiMaXhl+vYh1D8gA==",
+ "z9cd+Qj+ueX34Zf3997MNQ==",
+ "1dsKN1nG6upj7kKTKuJWsQ==",
+ "UtLYUlQJ02oKcjNR3l+ktg==",
+ "O538ibsrI4gkE5tfwjxjmg==",
+ "G736AX070whraDxChqUrqw==",
+ "THs1r8ZEPChSGrrhrNTlsA==",
+ "pVG1hL96/+hQ+58rJJy6/A==",
+ "1BjsijOzgHt/0i36ZGffoQ==",
+ "6rIWazDEWU5WPZHLkqznuQ==",
+ "cdWUm6uLNzR/knuj2x75eA==",
+ "nsnX3tKkN1elr18E31tXDw==",
+ "0fnruVOCxEczscBuv4yL9A==",
+ "SVuEYfQ9FGyVMo1672n0Yg==",
+ "ZRWyfXyXqAaOEjkzWl949Q==",
+ "S2MAIYeDQeJ1pl9vhtYtUg==",
+ "vsRNZx4thFFFPneubKq1Fw==",
+ "kuWGANwzNRpG4XmY7KjjNg==",
+ "i6r+mZfyhZyqlYv56o0H+w==",
+ "wqWqe0KRjZlUIrGgEOG9Mg==",
+ "t5wh9JGSkQO78QoQoEqvXA==",
+ "AGoVLd0QPcXnTedT5T95JQ==",
+ "aRrcmH+Ud3mF1vEXcpEm4w==",
+ "C65PZm8rZxJ6tTEb6d08Eg==",
+ "oAHVGBSJ2cf4dVnb/KEYmw==",
+ "BuDVDLl0OGdomEcr+73XhQ==",
+ "bLsStF0DDebpO+xulqGNtg==",
+ "xukOAM0QVsA72qEy0yku9A==",
+ "LpoayYsTO8WLFLCSh2kf2w==",
+ "LEVYAE54618FrlXkDN01Kw==",
+ "Jm862vBTCYbv/V4T1t46+Q==",
+ "X4kdXUuhcUqMSduqhfLpxA==",
+ "cLR0Ry4/N5swqga1R6QDMw==",
+ "0klouNfZRHFFpdHi4ZR2hA==",
+ "JGx8sTyvr4bLREIhSqpFkw==",
+ "ZiJ/kJ9GneF3TIEm08lfvQ==",
+ "hP7dSa8lLn9KTE/Z0s4GVQ==",
+ "600bwlyhcy754W1E6tuyYg==",
+ "U49SfOBeqQV9wzsNkboi8Q==",
+ "5DDb7fFJQEb3XTc3YyOTjg==",
+ "6uT7LZiWjLnnqnnSEW4e/Q==",
+ "tq5xUJt8GtjDIh1b48SthQ==",
+ "eJFIQh/TR7JriMzYiTw4Sg==",
+ "jdRzkUJrWxrqoyNH9paHfQ==",
+ "RKVDdE1AkILTFndYWi9wFg==",
+ "AEpTVUQhIEJGlXJB6rS26A==",
+ "PD+yHtJxZJ2XEvjIPIJHsQ==",
+ "dOS+mVCy3rFX9FvpkTxGXA==",
+ "lz+SeifYXxamOLs1FsFmSQ==",
+ "QTz21WkhpPjfK8YoBrpo+w==",
+ "9wUIeSgNN36SFxy8v2unVg==",
+ "ash1r2J6B0PUxJe8P0otVQ==",
+ "y7yS9x3yshVhMpDbQtfYOQ==",
+ "f07bdNVAe9x+cAMdF1bByQ==",
+ "N2KovXW14hN/6+iWa1Yv3g==",
+ "2DNbXVgesUa7PgYQ4zX5Lw==",
+ "WQznrwqvMhUlM3CzmbhAOQ==",
+ "FpWDTLTDmkUhH/Sgo+g1Gg==",
+ "OVHqwV8oQMC5KSMzd5VemA==",
+ "Bv4mNIC72KppYw/nHQxfpQ==",
+ "MI+HSMRh8KTW+Afiaxd/Fw==",
+ "10OltdxPXOvfatJuwPVKbQ==",
+ "y4/HohCJxtt+cT7nLJB08w==",
+ "RhcqXY4OsZlVVF7ZlkTeRw==",
+ "/mrqas0eDX+sFUNJvCQY8g==",
+ "ZIZx4MehWTVXPN9cVQBmyA==",
+ "z20AAnvj7WsfJeOu3vemlA==",
+ "dL6n/JsK+Iq6UTbQuo/GOw==",
+ "rMm9bHK69h0fcMkMdGgeeA==",
+ "ftsf2qztw3NC78ep/CZXWQ==",
+ "/n1RLTTVpygre1dl36PDwQ==",
+ "/FsJYFNe+7UvsSkiotNJEQ==",
+ "Yy2pPhITTmkEwoudXizHqQ==",
+ "lizovLQxu6L9sbafNQuShQ==",
+ "XV5MYe0Q7YMtoBD6/iMdSw==",
+ "5jHgQF4SfO/zy9xy9t+9dw==",
+ "16iT/jCcPDrJEfi2bE5F+Q==",
+ "syeBfQBUmkXNWCZ1GV8xSA==",
+ "sr3UXbMg5zzkRduFx/as7g==",
+ "xUXEE7OBBCudsQnuj5ycOA==",
+ "ojZY7Gi2QJXE/fp6Wy31iA==",
+ "RlNPyhgYOIn28R4vKCVtYA==",
+ "KOm8PTa+ICgDrgK9QxCJZw==",
+ "DJoy1NSZZw87oxWGlNHhfg==",
+ "jEdanvXKyZdZJG6mj/3FWw==",
+ "Omr+zPWVucPCSfkgOzLmSQ==",
+ "71w3aSvuh2mBLtdqJCN3wA==",
+ "xjTMO2mvtpvwQrounD4e8g==",
+ "Zz/5VMbw1TqwazReplvsEg==",
+ "hIjgi20+km+Ks23NJ4VQ6Q==",
+ "00TVKawojyqrJkC7YqT41Q==",
+ "YgVpC5d5V6K/BpOD663yQA==",
+ "wX70jKLKJApHnhyK0r6t3A==",
+ "lacCCRiWdquNm4YRO7FoKA==",
+ "cWdlhVZD7NWHUGte24tMjg==",
+ "t5U+VMsTtlWAAWSW+00SfQ==",
+ "AMfL0rH+g8c0VqOUSgNzQw==",
+ "0G93AxGPVwmr66ZOleM90A==",
+ "9tiibT8V9VwnPOErWGNT3w==",
+ "+dBv88reDrjEz6a2xX3Hzw==",
+ "xX6atcCApI08oVLjjLteLg==",
+ "+YrqTEJlJCv0A2RHQ8tr1A==",
+ "aqcOby9QyEbizPsgO3g0yw==",
+ "s/BZAhh1cTV3JCDUQsV8mA==",
+ "x9VwDdFPp/rJ+SF16ooWYg==",
+ "k/OVIllJvW6BefaLEPq7DA==",
+ "rIMXaCaozDvrdpvpWvyZOQ==",
+ "qQQwJ/aF87BbnLu3okXxaw==",
+ "TIWSM78m0RprwgPGK/e0JA==",
+ "r/b5px/UImGNjT/X5sYjuA==",
+ "7K8l6KoP0BH82/WMLntfrg==",
+ "gEHGeR2F82OgBeAlnYhRSw==",
+ "1/SGIab+NnizimUmNDC4wA==",
+ "WADmxH7R6B4LR+W6HqQQ6A==",
+ "pcoBh5ic7baSD4TZWb3BSw==",
+ "es/L9iW8wsyLeC5S4Q8t+g==",
+ "D175i+2bZ7aWa4quSSkQpA==",
+ "WQMffxULFKJ+bun6NrCURA==",
+ "82hTTe1Nr4N2g7zwgGjxkw==",
+ "oyYtf08AkWLR52bXm5+sKw==",
+ "8uP4HUnSodw88yoiWXOIcw==",
+ "x2NpqNnqRihktNzpxmepkQ==",
+ "x5zMDuW66467ofgL3spLUQ==",
+ "OMO4pqzfcbQ11YO4nkTXfg==",
+ "N4/mQFyhDpPzmihjFJJn6w==",
+ "NN/ymVQNa17JOTGr6ki3eQ==",
+ "htDbVu1xGhCRd8qoMlBoMg==",
+ "S47hklz3Ow+n5aY6+qsCoA==",
+ "ji+1YHlRvzevs3q5Uw1gfA==",
+ "3Y4w0nETru3SiSVUMcWXqw==",
+ "XfBOCJwi2dezYzLe316ivw==",
+ "kMUdiwM7WR8KGOucLK4Brw==",
+ "V/xG5QFyx1pihimKmAo8ZA==",
+ "sQskMBELEq86o1SJGQqfzg==",
+ "6+jhreeBLfw64tJ+Nhyipw==",
+ "8iYdEleTXGM+Wc85/7vU9w==",
+ "D7piVoB2NJlBxK5owyo4+g==",
+ "hDGa2yLwNvgBd/v6mxmQaQ==",
+ "WLsh3UF4WXdHwgnbKEwRlQ==",
+ "D5jaV+HtXkSpSxJPmaBDXg==",
+ "jCgdKXsBCgf7giUKnr6paQ==",
+ "XqW7UBTobbV4lt1yfh0LZw==",
+ "EbGG4X18upaiVQmPfwKytg==",
+ "dXDPnL1ggEoBqR13aaW9HA==",
+ "Vik8tGNxO0xfdV0pFmmFDw==",
+ "Swjn3YkWgj0uxbZ1Idtk+A==",
+ "JPxEncA4IkfBDvpjHsQzig==",
+ "F5FcNti7lUa9DyF2iEpBug==",
+ "HJYgUxFZ66fRT8Ka73RaUg==",
+ "Jbxl8Nw1vlHO9rtu0q/Fpg==",
+ "fmC+85h5WBuk8fDEUWPjtQ==",
+ "dZgMquvZmfLqP4EcFaWCiA==",
+ "XF/yncdoT4ruPeXCxEhl9Q==",
+ "QJEbr3+42P9yiAfrekKdRQ==",
+ "Sr9c0ReRpkDYGAiqSy683g==",
+ "Nr4zGo5VUrjXbI8Lr4YVWQ==",
+ "NDZWIhhixq7NT8baJUR4VQ==",
+ "GFRJoPcXlkKSvJRuBOAYHQ==",
+ "WHutPin+uUEqtrA7L8878A==",
+ "2rhjiY0O0Lo36wTHjmlNyw==",
+ "XsF7R12agx/KkRWl0TyXRA==",
+ "R6cO8GzYfOGTIi773jtkXw==",
+ "zrZWcqQsUE3ocWE0fG+SOA==",
+ "uNzpptKjihEfKRo5A1nWmw==",
+ "gICaI06E9scnisonpvqCsA==",
+ "TA9WjiLAFgJubLN4StPwLw==",
+ "sBpytpE38xz0zYeT+0qc2A==",
+ "Ej7W3+67kCIng3yulXGpRQ==",
+ "nR3ACzeVF5YcLX6Gj6AGyQ==",
+ "b0vZfEyuTja2JYMa20Rtbg==",
+ "f1h+Vp+xmdZsZIziHrB2+g==",
+ "WzjvUJ4jZAEK7sBqw+m07A==",
+ "OzMR5D2LriC5yrVd5hchnA==",
+ "cw1gBLtxH/m4H7dSM7yvFg==",
+ "CZbd+UoTz0Qu1kkCS3k8Xg==",
+ "WtT0QAERZSiIt2SFDiAizg==",
+ "QsquNcCZL9wv7oZFqm64vQ==",
+ "FXzaxi3nAXBc8WZfFElQeA==",
+ "Ml3mi1lGS1IspHp3dYYClg==",
+ "XGAXhUFjORwKmAq9gGEcRg==",
+ "wOhbpTzmFla8R0kI9OiHaA==",
+ "qoK2keBg3hdbn7Q24kkVXg==",
+ "ZAQHWU6RMg4IadOxuaukyw==",
+ "RiahBXX2JbPzt8baPiP/8g==",
+ "Qx6rVv9Xj8CBjqikWI9KFA==",
+ "ZRnR6i+5WKMRfs3BDRBCJg==",
+ "91LQuW6bMSxl10J/UDX23A==",
+ "0dIeIM5Zvm5nSVWLy94LWg==",
+ "Ja3ECL7ClwDrWMTdcSQ6Ug==",
+ "f6iLrMpxKhFxIlfRsFAuew==",
+ "iSeH0JFSGK73F470Rhtesw==",
+ "DwOTyyCoUfaSShHZx9u6xg==",
+ "rdeftHE7gwAT67wwhCmkYQ==",
+ "kUhyc3G8Zvx8+q5q5nVEhw==",
+ "W8bATujVUT80v2XGJTKXDg==",
+ "dMRx4Mf6LrN64tiJuyWmDw==",
+ "9cvHJmim9e0pOaoUEtiM6A==",
+ "RHToSGASrwEmvzjX6VPvNQ==",
+ "V7eji28JSg3vTi30BCS7gw==",
+ "4+htiqjEz9oq0YcI/ErBVg==",
+ "jKJn4czwUl/6wtZklcMsSg==",
+ "bvyB6OEwhwCIfJ6KRhjnRw==",
+ "59ipbMH7cKBsF9bNf4PLeQ==",
+ "M/cQja3uIk1im9++brbBOA==",
+ "AChOz8avRYsvxlbWcorQ3w==",
+ "FcKjlHKfQAGoovtpf+DxWQ==",
+ "y+cl1/Knb9MZPz8nBB0M+w==",
+ "b8BZV1NfBdLi70ir4vYvZg==",
+ "aFJuE/s+Kbge4ppn+wulkA==",
+ "CWBGcRFYwZ0va6115vV/oQ==",
+ "glnqaRfwm6NxivtB2nySzw==",
+ "mPk1IsU5DmDFA/Ym5+1ojw==",
+ "LGwcvetzQ3QqKjNh5vA8vw==",
+ "yctId8ltkl3+xqi9bj+RqA==",
+ "spJI3xFUlpCDqzg0XCxopA==",
+ "V8m51xgUgywRoV6BGKUrgg==",
+ "rgcXxjx3pDLotH7TTfAoZw==",
+ "/TSsi/AwKHtP6kQaeReI3w==",
+ "8dbyfox/isKLsnVjQNsEXg==",
+ "MOrAbuJTyGKPC6MgYJlx5Q==",
+ "uNWFZlP7DA96sf+LWiAhtQ==",
+ "hNHqznsrIVRSQdII6crkww==",
+ "GT6WUDXiheKAM7tPg3he9A==",
+ "JC8Q+8yOJ52NvtVeyHo68w==",
+ "HMQarkPWOUDIg5+5ja2dBQ==",
+ "nknBKPgb7US42v8A0fTl/w==",
+ "fDOUzPTU2ndpbH0vgkgrJQ==",
+ "GTNttXfMniNhrbhn92Aykg==",
+ "D2JcY4zWwqaCKebLM8lPiQ==",
+ "/c34NtdUZAHWIwGl3JM8Tw==",
+ "/G26n5Xoviqldr5sg/Jl3w==",
+ "GF0lY77rx1NQzAsZpFtXIQ==",
+ "BMOi5JmFUg5sCkbTTffXHw==",
+ "R+beucURp/H5jLs4kW6wmg==",
+ "xfYZ6qhWNBqqJ0PdWRjOwA==",
+ "Ahpi9+nl13kPTdzL+jgqMw==",
+ "oIU19xAvLJwQSZzIH577aA==",
+ "50xwiYvGQytEDyVgeeOnMg==",
+ "M0ESOGwJ4WZ4Ons1ljP0bQ==",
+ "fS471/rN4K2m10mUwGFuLg==",
+ "RrE3B3X/SJi3CqCUlTYwaw==",
+ "oDca3JEdRb4vONT9GUUsaQ==",
+ "pHo1O5zrCHCiLvopP2xaWw==",
+ "7sCJ4RxbxRqVnF4MBoKfuQ==",
+ "7R5rFaXCxM3moIUtoCfM2g==",
+ "4rrSL6N0wyucuxeRELfAmw==",
+ "9Gkw+hvsR/tFY1cO89topg==",
+ "aw4CzX8pYbPVMuNrGCEcWg==",
+ "KyLQxi5UP+qOiyZl0PoHNQ==",
+ "T1pMWdoNDpIsHF8nKuOn2A==",
+ "Qv6wWP4PpycDGxe7EZNSCw==",
+ "ZJc7GV0Yb6MrXkpDVIuc8g==",
+ "aXrbsro7KLV8s4I4NMi4Eg==",
+ "7k5rBuh8FbTTI4TP87wBPQ==",
+ "NRyFx6jqO/oo9ojvbYzsAg==",
+ "P7eMlOz9YUcJO+pJy0Kpkw==",
+ "jpjpNjL1IKzJdGqWujhxCw==",
+ "9k1u/5TgPmXrsx3/NsYUhg==",
+ "c1wbFbN7AdUERO/xVPJlgw==",
+ "Yw4ztKv6yqxK9U1L0noFXg==",
+ "GnJKlRzmgKN9vWyGfMq3aA==",
+ "91VcAVv7YDzkC1XtluPigw==",
+ "h1NNwMy0RjQmLloSw1hvdg==",
+ "pzC8Y0Vj9MPBy3YXR32z6w==",
+ "UTmTgvl+vGiCDQpLXyVgOg==",
+ "CzWhuxwYbNB/Ffj/uSCtbw==",
+ "VOB+9Bcfu8aHKGdNO0iMRw==",
+ "X2Tawm2Cra6H7WtXi1Z4Qw==",
+ "6cTETZ9iebhWl+4W5CB+YQ==",
+ "X4hrgqMIcApsjA9qOWBoCw==",
+ "1buQEv2YlH/ljTgH0uJEtw==",
+ "FH5Z60RXXUiDk+dSZBxD3g==",
+ "FI2WhaSMb3guFLe3e9il8Q==",
+ "O/EizzJSuFY8MpusBRn7Tg==",
+ "b6rrRA0W247O+FfvDHbVCQ==",
+ "ng1Q0A7ljho3TUWWYl46sw==",
+ "1Ym0lyBJ9aFjhJb/GdUPvQ==",
+ "+OXdvbTxHtSoLg7bZMho4w==",
+ "cuQslgfqD2VOMhAdnApHrA==",
+ "pCQmlnn3BxhsV2GwqjRhXg==",
+ "6PzjncEw2wHZg7SP7SQk9w==",
+ "nqtQI1bSM7DCO9P1jGV97Q==",
+ "O1ckWUwuhD44MswpaD6/rw==",
+ "RUmhye56tQu9xXs4SRJpOQ==",
+ "llujnWE17U8MIHmx4SbrSA==",
+ "UwqBVd4Wfias4ElOjk2BzQ==",
+ "kBAB2PSjXwqoQOXNrv80AA==",
+ "w1zN28mSrI/gqHsgs4ME3A==",
+ "301utVPZ93AnPLYbsiJggw==",
+ "qIFpKKwUmztsBpJgMaVvSg==",
+ "QmcURiMzmVeUNaYPSOtTTg==",
+ "x/MpsQvziUpW40nNUHDS5Q==",
+ "t1O9jSNjg4DTIv/Za4NbtA==",
+ "1B5gxGQSGzVKoNd5Ol4N7g==",
+ "81iQLU+YwxNwq4of6e9z7A==",
+ "x0eIHCvQLd2jdDaXwSWTYQ==",
+ "96ORaz1JRHY1Gk8H74+C2g==",
+ "bNDKcFu8T5Y6OoLSV+o/Sw==",
+ "WrJMOuXSLKKzgmIDALkyNw==",
+ "+gpHnUj2GWocP74t5XWz4w==",
+ "z5DveTu377UW8IHnsiUGZg==",
+ "irnD9K8bsT+up/JUrxPw6A==",
+ "ginkFyNVMwkZLE49AbfqfA==",
+ "2hEzujfG3mR5uQJXbvOPTQ==",
+ "E9yeifEZtpqlD0N3pomnGw==",
+ "OpC/sL320wl5anx6AVEL+A==",
+ "D7wN7b5u5PKkMaLJBP9Ksw==",
+ "83WGpQGWyt6mCV+emaomog==",
+ "X6ulLp4noBgefQTsbuIbYQ==",
+ "BH+rkZWQjTp7au6vtll/CQ==",
+ "Ex3x5HeDPhgO2S9jjCFy4g==",
+ "YNqIHCmBp/EbCgaPKJ7phw==",
+ "312g8iTB9oJgk/OqcgR7Cw==",
+ "LcF0OqPWrcpHby8RwXz1Yg==",
+ "gaEtlJtD6ZjF5Ftx0IFt0A==",
+ "bvbMJZMHScwjJALxEyGIyg==",
+ "StoXC7TBzyRViPzytAlzyQ==",
+ "XqFSbgvgZn0CpaZoZiRauQ==",
+ "AqHVaj3JcR44hnMzUPvVYg==",
+ "jTg9Y6EfpON4CRFOq0QovA==",
+ "q/siBRjx6wNu+OTvpFKDwA==",
+ "goSgZ8N5UbT5NMnW3PjIlQ==",
+ "9onh6QKp70glZk9cX3s34A==",
+ "o5XVEpdP4OXH0NEO4Yfc/A==",
+ "a5gZ5uuRrXEAjgaoh7PXAg==",
+ "PaROi5U16Tk35p0EKX5JpA==",
+ "dtnE401dC0zRWU0S/QOTAg==",
+ "7J3FoFGuTIW36q0PZkgBiw==",
+ "hiYg+aVzdBUDCG0CXz9kCw==",
+ "vhdFtKVH4bVatb4n8KzeXw==",
+ "DWKsPfKDAtfuwgmc2dKUNg==",
+ "M2JMnViESVHTZaru6LDM6w==",
+ "G/PA+kt0N+jXDVKjR/054A==",
+ "6rqK8sjLPJUIp7ohkEwfZg==",
+ "wajwXfWz2J+O+NVaj6j2UQ==",
+ "C4QEzQKGxyRi2rjwioHttA==",
+ "N/HgDydvaXuJvTCBhG/KtA==",
+ "6erpZS36qZRXeZ9RN9L+kw==",
+ "bbBsi6tXMVWyq3SDVTIXUg==",
+ "aySnrShOW4/xRSzl/dtSKQ==",
+ "rxfACPLtKXbYua18l3WlUw==",
+ "L4+C6I7ausPl6JbIbmozAg==",
+ "R3ijnutzvK6IKV3AKHQZSA==",
+ "leDlMcM+B1mDE8k5SWtUeg==",
+ "KGI/cXVz6v6CfL8H6akcUQ==",
+ "NtwqUO3SKZE/9MXLbTJo/g==",
+ "dJHKDkfMFJeoULg7U4wwDQ==",
+ "IEz72W2/W8xBx5aCobUFOQ==",
+ "wUYhs4j3W9nIywu1HIv2JA==",
+ "GzbeM7snhe+M+J7X+gAsQw==",
+ "3/1puZTGSrD9qNKPGaUZww==",
+ "eKQCVzLuzoCLcB4im8147A==",
+ "CCK+6Dr72G3WlNCzV7nmqw==",
+ "CJoZn5wdTXbhrWO5LkiW0g==",
+ "bJ1cZW7KsXmoLw0BcoppJg==",
+ "OlpA9HsF8MBh7b45WZSSlg==",
+ "JZRjdJLgZ+S0ieWVDj8IJg==",
+ "uhT12XY79CtbwhcSfAmAXQ==",
+ "isep9d+Q7DEUf0W7CJJYzw==",
+ "K9A87aMlJC8XB9LuFM913g==",
+ "uqe3rFveJ2JIkcZQ3ZMXHQ==",
+ "0e8hM3E5tnABRyy29A8yFw==",
+ "4iiCq+HhC+hPMldNQMt0NA==",
+ "X4o0OkTz0ec70mzgwRfltA==",
+ "1E3pMgAHOnHx3ALdNoHr8Q==",
+ "xNilc7UOu1kyP0+nK5MrLw==",
+ "DQlZWBgdTCoYB1tJrNS5YQ==",
+ "iruDC5MeywV4yA8o1tw/KQ==",
+ "z+1oDVy8GJ5u/UDF+bIQdA==",
+ "uExgqZkkJnZj252l5dKAGg==",
+ "ZgdpqFrVGiaHkh9o3rDszg==",
+ "5N2oi2pB69NxeNt08yPLhw==",
+ "G37U8XTFyshfCs7qzFxATg==",
+ "0ZEC3hy411LkOhKblvTcqg==",
+ "ITZ3P47ALS0JguFms6/cDA==",
+ "WWN44lbUnEdHmxSfMCZc6w==",
+ "r2f2MyT+ww1g9uEBzdYI1w==",
+ "ZvvxwDd0I6MsYd7aobjLUA==",
+ "uQs79rbD/wEakMUxqMI48A==",
+ "022B0oiRMx8Xb4Af98mTvQ==",
+ "afMd/Hr3rYz/l7a3CfdDjg==",
+ "xmsYnsJq78/f9xuKuQ2pBQ==",
+ "dFetwmFw+D6bPMAZodUMZQ==",
+ "TBQpcKq2huNC5OmI2wzRQw==",
+ "skrQRB9xbOsiSA19YgAdIQ==",
+ "anyANMnNkUqr3JuPJz5Qzw==",
+ "6QUGE2S8oFYx4T4nW56cCw==",
+ "rwtF86ZAbWyKI6kLn4+KBw==",
+ "6txm8z4/LGCH0cpaet/Hsg==",
+ "wdRyYjaM11VmqkkxV/5bsA==",
+ "+k5lDb+QdNc9iZ01hL5yBg==",
+ "k/pBSWE2BvUsvJhA9Zl5uw==",
+ "jQjyjWCEo9nWFjP4O8lehw==",
+ "R6Me6sSGP5xpNI8R0xGOWw==",
+ "9+hjTVMQUsvVKs7Tmp52tg==",
+ "VQIpquUqmeyt/q6OgxzduQ==",
+ "KXvdjZ3rRKn60djPTCENGA==",
+ "5HovoyHtul8lXh+z8ywq9A==",
+ "1+XWdu4qCqLLVjqkKz3nmA==",
+ "LCj4hI520tA685Sscq6uLw==",
+ "b53qqLnrTBthRXmmnuXWvw==",
+ "WTr3q/gDkmB4Zyj7Ly20+w==",
+ "FbxScyuRacAQkdQ034ShTA==",
+ "qaTdVEeZ6S8NMOxfm+wOMA==",
+ "ZNrjP1fLdQpGykFXoLBNPw==",
+ "/Bwpt5fllzDHq2Ul6v86fA==",
+ "/mFp3GFkGNLhx2CiDvJv4A==",
+ "RppDe/WGt1Ed6Vqg1+cCkQ==",
+ "6M6QapJ5xtMXfiD3bMaiLA==",
+ "Ghuj9hAyfehmYgebBktfgA==",
+ "GncGQgmWpI/fZyb/6zaFCg==",
+ "R1TCCfgltnXBvt5AiUnCtQ==",
+ "5NEP7Xt7ynj6xCzWzt21hQ==",
+ "4yEkKp2FYZ09mAhw2IcrrA==",
+ "y2Tn2gmhKs5WKc01ce74rg==",
+ "wnfYUctNK+UPwefX5y4/Rw==",
+ "BV1moliPL15M14xkL+H1zw==",
+ "80C9TB9/XT1gGFfQDJxRoA==",
+ "yL1DwlIIREPuyuCFULi0uw==",
+ "D09afzGpwCEH0EgZUSmIZA==",
+ "eCy/T+a8kXggn1L8SQwgvA==",
+ "+dIEf5FBrHpkjmwUmGS6eg==",
+ "kzXsrxWRnWhkA82LsLRYog==",
+ "Nf9fbRHm844KZ2sqUjNgkA==",
+ "XAq/C+XyR6m3uzzLlMWO5Q==",
+ "jiV+b/1EFMnHG6J0hHpzBg==",
+ "HK0yf7F97bkf1VYCrEFoWA==",
+ "Cz1G77hsDtAjpe0WzEgQog==",
+ "xdCCdP8SNBOK3IsX6PiPQA==",
+ "8snljTGo/uICl9q0Hxy7/A==",
+ "sLdxIKap0ZfC3GpUk3gjog==",
+ "IA1jmtfpYkz/E2wD0+27WA==",
+ "PPa7BDMpRdxJdBxkuWCxKA==",
+ "CuGIxWhRLN7AalafBZLCKQ==",
+ "MWcV03ULc0vSt/pFPYPvFA==",
+ "QVwuN66yPajcjiRnVk/V8g==",
+ "aLY2pCT0WfFO5EJyinLpPg==",
+ "dGrf9SWJ13+eWS6BtmKCNw==",
+ "YtZ8CYfnIpMd2FFA5fJ+1Q==",
+ "Umd+5fTcxa3mzRFDL9Z8Ww==",
+ "Al8+d/dlOA5BXsUc5GL8Tg==",
+ "/KYZdUWrkfxSsIrp46xxow==",
+ "kr8tw1+3NxoPExnAtTmfxg==",
+ "PwvPBc+4L73xK22S9kTrdA==",
+ "VWNDBOtjiiI4uVNntOlu/A==",
+ "lJFPmPWcDzDp5B2S8Ad8AA==",
+ "Mofqu40zMRrlcGRLS42eBw==",
+ "BuENxPg7JNrWXcCxBltOPg==",
+ "nmD7fEU4u7/4+W/pkC4/0Q==",
+ "axEl7xXt/bwlvxKhI7hx4g==",
+ "W04GeDh+Tk/I1S85KlozRA==",
+ "tVw8U1AsslIFmQs4H1xshg==",
+ "TSPFvkgw6uLsJh66Ou0H9w==",
+ "IYIbEaErHoFBn8sTT9ICIQ==",
+ "WBu0gJmmjVdVbjDmQOkU6w==",
+ "ZgjifTVKmxOieco81gnccQ==",
+ "ZrCnZB/U/vcqEtI1cSvnww==",
+ "2D6yhuABiaFFoXz0Lh0C+w==",
+ "SfwnYZCKP1iUJyU1yq4eKg==",
+ "tsiqwelcBAMU/HpLGBtMGw==",
+ "S9L29U2P5K8wNW+sWbiH7w==",
+ "sGLPmr568+SalaQr8SE/PA==",
+ "Hm6MG6BXbAGURVJKWRM6ZA==",
+ "euxzbIq4vfGYoY3s1QmLcw==",
+ "/FchS2nPezycB8Bcqc2dbg==",
+ "ZKvox7BaQg4/p5jIX69Umw==",
+ "HkbdaMuDTPBDnt3wAn5RpQ==",
+ "eddhS+FkXxiUnbPoCd5JJw==",
+ "Muf2Eafcf9G3U2ZvQ9OgtQ==",
+ "a7Pv1SOWYnkhIUC22dhdDA==",
+ "O839JUrR+JS30/nOp428QA==",
+ "2qK2ZEY9LgdKSTaLf6VnLA==",
+ "BTiGLT6XdZIpFBc91IJY6g==",
+ "EqYq2aVOrdX5r7hBqUJP7g==",
+ "SIuKH/Qediq0TyvqUF93HQ==",
+ "c5ymZKqx/td1MiS2ERiz9A==",
+ "rqucO37p86LpzehR/asCSQ==",
+ "1tpM0qgdo7JDFwvT0TD78g==",
+ "Ar1Eb/f/LtuIjXnnVPYQlA==",
+ "V8q+xz4ljszLZMrOMOngug==",
+ "P5WPQc5NOaK7WQiRtFabkw==",
+ "Xo8ZjXOIoXlBjFCGdlPuZw==",
+ "jTmPbq+wh30+yJ/dRXk1cA==",
+ "KSumhnbKxMXQDkZIpDSWmQ==",
+ "Kh/J1NpDBGoyDU+Mrnnxkg==",
+ "3BjLFon1Il0SsjxHE2A1LQ==",
+ "dml2gqLPsKpbIZ93zTXwCQ==",
+ "ZyoaR1cMiKAsElmYZqKjLA==",
+ "vnOJ3e9Zd4wPx8PX7QgZzQ==",
+ "2melaInV0wnhBpiI3da6/A==",
+ "mUek9NkXm8HiVhQ6YXiyzA==",
+ "RZTpYKxOAH9JgF1QFGN+hw==",
+ "a/Y6IAVFv0ykRs9WD+ming==",
+ "yhRi5M9Etuu9HSu4d24i3w==",
+ "+1gcqAqaRZwCj5BGiZp3CA==",
+ "o1zeXHJEKevURAAbUE/Vog==",
+ "cvOg7N4DmTM+ok1NBLyBiQ==",
+ "uPdjKJIGzN7pbGZDZdCGaA==",
+ "REnDNe9mGfqVGZt+GdsmjQ==",
+ "XqTK/2QuGWj50tGmiDxysA==",
+ "bL2FuwsPT7a7oserJQnPcw==",
+ "uO+uK1DntCxVRr1KttfUIw==",
+ "Xconi1dtldH90Wou9swggw==",
+ "HRF3WL/ue3/QlYyu7NUTrA==",
+ "5LuFDNKzMd2BzpWEIYO2Ww==",
+ "dNTU+/2DdZyGGTdc+3KMhQ==",
+ "H+NHjk/GJDh/GaNzMQSzjg==",
+ "/Ph/6l/lFNVqxAje1+PgFA==",
+ "4WRdAjiUmOQg2MahsunjAg==",
+ "j+lDhAnWAyso+1N8cm85hQ==",
+ "nFBXCPeiwxK9mLXPScXzTA==",
+ "vGKknndb4j6VTV8DxeT4fQ==",
+ "fdqt93OrpG13KAJ5cASvkg==",
+ "1MIn73MLroxXirrb+vyg2Q==",
+ "Q7teXmTHAC5qBy+t7ugf0w==",
+ "bWwtTFlhO3xEh/pdw0uWaQ==",
+ "Omi2ZB9kdR1HrVP2nueQkA==",
+ "+ZozWaPWw8ws1cE5DJACeg==",
+ "3FH4D31nKV13sC9RpRZFIg==",
+ "4kXlJNuT79XXf1HuuFOlHw==",
+ "36XDmX6j542q+Oei1/x0gw==",
+ "MqqDg9Iyt4k3vYVW5F+LDw==",
+ "cvrGmub2LoJ+FaM5HTPt9A==",
+ "uC2lzm7HaMAoczJO6Z/IhQ==",
+ "MnStiFQAr3QlaRZ02SYGaQ==",
+ "ZuayB6IpbeITokKGVi9R5w==",
+ "FtxpWdhEmC6MT61qQv4DGA==",
+ "KujFdhhgB9q4oJfjYMSsLg==",
+ "ZV8mEgJweIYk0/l0BFKetA==",
+ "gDLjxT7vm07arF4SRX5/Vg==",
+ "/MEOgAhwb7F0nBnV4tIRZA==",
+ "k2KP9oPMnHmFlZO6u6tgyw==",
+ "fbTm027Ms0/tEzbGnKZMDA==",
+ "HOi+vsGAae4vhr+lJ5ATnQ==",
+ "9Bet5waJF5/ZvsYaHUVEjQ==",
+ "Wd0dOs7eIMqW5wnILTQBtg==",
+ "z/e5M2lE9qh3bzB97jZCKA==",
+ "b16O4LF7sVqB7aLU2f3F1A==",
+ "lsBTMnse2BgPS6wvPbe7JA==",
+ "0nOg18ZJ/NicqVUz5Jr0Hg==",
+ "MFeXfNZy6Q9wBfZmPQy3xg==",
+ "ksOFI9C7IrDNk4OP6SpPgw==",
+ "NquRbPn8fFQhBrUCQeRRoQ==",
+ "ccmy4GVuX967KaQyycmO0w==",
+ "DY0IolKTYlW+jbKLPAlYjQ==",
+ "aJFbBhYtMbTyMFBFIz/dTA==",
+ "9pdeedz1UZUlv8jPfPeZ1g==",
+ "qZ2q5j2gH3O56xqxkNhlIA==",
+ "N7fHwb397tuQHtBz1P80ZQ==",
+ "uOkMpYy/7DYYoethJdixfQ==",
+ "E9ajQQMe02gyUiW3YLjO/A==",
+ "dFSavcNwGd8OaLUdWq3sng==",
+ "TAD0Lk95CD86vbwrcRogaQ==",
+ "jLI3XpVfjJ6IzrwOc4g9Pw==",
+ "CzP13PM/mNpJcJg8JD3s6w==",
+ "GSWncBq4nwomZCBoxCULww==",
+ "9k17UqdR1HzlF7OBAjpREA==",
+ "TrWS+reCJ0vbrDNT5HDR9w==",
+ "CXMKIdGvm60bgfsNc+Imvg==",
+ "6NP81geiL14BeQW6TpLnUA==",
+ "hW9DJA1YCxHmVUAF7rhSmQ==",
+ "8M0kSvjn5KN8bjsMdUqKZQ==",
+ "eS/vTdSlMUnpmnl1PbHjyw==",
+ "h2B0ty0GobQhDnFqmKOpKQ==",
+ "n7KL1Kv027TSxBVwzt9qeA==",
+ "yYmnM/WOgi+48Rw7foGyXA==",
+ "FhthAO5IkMyW4dFwpFS7RA==",
+ "81ZH3SO0NrOO+xoR/Ngw1g==",
+ "t7HaNlXL16fVwjgSXmeOAQ==",
+ "N+K1ibXAOyMWdfYctNDSZQ==",
+ "yQCLV9IoPyXEOaj3IdFMWw==",
+ "3+zsjCi7TnJhti//YXK35w==",
+ "600mjiWke4u0CDaSQKLOOg==",
+ "K4VS+DDkTdBblG93l2eNkA==",
+ "5KOgetfZR+O2wHQSKt41BQ==",
+ "kj5WqpRCjWAfjM7ULMcuPQ==",
+ "AxEjImKz4tMFieSo7m60Sg==",
+ "jp5Em/0Ml4Txr1ptTUQjpg==",
+ "jQVlDU+HjZ2OHSDBidxX5A==",
+ "4NHQwbb3zWq2klqbT/pG6g==",
+ "PeJS+mXnAA6jQ0WxybRQ8w==",
+ "l6Ssc04/CnsqUua9ELu2iQ==",
+ "nFPDZGZowr3XXLmDVpo7hg==",
+ "yYBIS9PZbKo7Gram7IXWPA==",
+ "/HU2+fBqfWTEuqINc0UZSA==",
+ "adT+OjEB2kqpeYi4kQ6FPg==",
+ "GW1Uaq622QamiiF24QUA0g==",
+ "rTwJggSxTbwIYdp07ly0LA==",
+ "4yrFNgqWq17zVCyffULocA==",
+ "vvh9vAIrXjIwLVkuJb5oDQ==",
+ "C7UaoIEXsVRxjeA0u99Qmw==",
+ "x1A74vg/hwwjAx6GrkU8zw==",
+ "7XRiYvytcwscemlxd9iXIQ==",
+ "64AA4jLHXc1Dp15aMaGVcA==",
+ "u/QxrP1NOM/bOJlJlsi/jQ==",
+ "5M3dFrAOemzQ0MAbA8bI5w==",
+ "wyqmQGB6vgRVrYtmB2vB7w==",
+ "8vLA9MOdmLTo3Qg+/2GzLA==",
+ "/u5W2Gab4GgCMIc4KTp2mg==",
+ "lhAOM81Ej6YZYBu45pQYgg==",
+ "MArbGuIAGnw4+fw6mZIxaw==",
+ "ZZImGypBWwYOAW43xDRWCQ==",
+ "L2IeUnATZHqOPcrnW2APbA==",
+ "bQKkL+/KUCsAXlwwIH0N3w==",
+ "f09F7+1LRolRL5nZTcfKGA==",
+ "hPnPQOhz4QKhZi02KD6C+A==",
+ "78b8sDBp28zUlYPV5UTnYw==",
+ "iVDd2Zk7vwmEh97LkOONpQ==",
+ "LHQETSI5zsejvDaPpsO29g==",
+ "Yjm5tSq1ejZn3aWqqysNvA==",
+ "gkrg0NR0iCaL7edq0vtewA==",
+ "Lo1xTCEWSxVuIGEbBEkVxA==",
+ "8GyPup4QAiolFJ9v80/Nkw==",
+ "3L3KEBHhgDwH615w4OvgZA==",
+ "hJSP7CostefBkJrwVEjKHA==",
+ "9oQ/SVNJ4Ye9lq8AaguGAQ==",
+ "n7Bns42aTungqxKkRfQ5OQ==",
+ "K5lhaAIZkGeP5rH2ebSJFw==",
+ "ZaPsR9X77SNt7dLjMJUh8A==",
+ "18ndtDM9UaNfBR1cr3SHdA==",
+ "0QbH4oI8IjZ9BRcqRyvvDQ==",
+ "J/eAtAPswMELIj8K2ai+Xg==",
+ "qenHZKKlTUiEFv6goKM/Mw==",
+ "vjrSYGUpeKOtJ2cNgLFg2g==",
+ "DA+3fjr7mgpwf6BZcExj0w==",
+ "rh7bzsTQ1UZjG7amysr0Gg==",
+ "tFMJRXfWE9g78O1uBUxeqQ==",
+ "e/nWuo5YalCAFKsoJmFyFA==",
+ "gqehq46BhFX2YLknuMv02w==",
+ "Uudn69Kcv2CGz2FbfJSSEA==",
+ "Otz/PgYOEZ1CQDW54FWJIQ==",
+ "IwfeA6d0cT4nDTCCRhK+pA==",
+ "jgNijyoj2JrQNSlUv4gk4A==",
+ "KzWdWPP2gH0DoMYV4ndJRg==",
+ "pv/m2mA/RJiEQu2Qyfv9RA==",
+ "ATmMzriwGLl+M3ppkfcZNA==",
+ "tVvWdA+JqH0HR2OlNVRoag==",
+ "n6QVaozMGniCO0PCwGQZ6w==",
+ "gU3gu8Y5CYVPqHrZmLYHbQ==",
+ "cBBOQn7ZjxDku0CUrxq2ng==",
+ "w+jzM0I5DRzoUiLS/9QIMQ==",
+ "MLlVniZ08FHAS5xe+ZKRaA==",
+ "wMyJLQJdmrC2TSeFkIuSvQ==",
+ "dG98w8MynOoX7aWmkvt+jg==",
+ "zm+z+OOyHhljV2TjA3U9zw==",
+ "Tk5MAqd1gyHpkYi8ErlbWg==",
+ "g6zSo8BvLuKqdmBFM1ejLA==",
+ "d0VAZLbLcDUgLgIfT1GmVQ==",
+ "SNPYH4r/J9vpciGN2ybP5Q==",
+ "XA2hUgq3GVPpxtRYiqnclg==",
+ "fVCRaPsTCKEVLkoF4y3zEw==",
+ "FpgdsQ2OG+bVEy3AeuLXFQ==",
+ "JquDByOmaQEpFb47ZJ4+JA==",
+ "e369ZIQjxMZJtopA//G55Q==",
+ "Nsd+DfRX6L54xs+iWeMjCQ==",
+ "+/UCpAhZhz368iGioEO8aQ==",
+ "e5l9ZiNWXglpw6nVCtO8JQ==",
+ "Cl1u5nGyXaoGyDmNdt38Bw==",
+ "6sNP0rzCCm3w976I2q2s/w==",
+ "qcpeZWUlPllQYZU6mHVwUw==",
+ "kzYddqiMsY3EYrpxve2/CQ==",
+ "3iC21ByW/YVL+pSyppanWw==",
+ "3HPOzIZxoaQAmWRy9OkoSg==",
+ "xsCZVhCk2qJmOqvUjK3Y8Q==",
+ "i2sSvrTh/RdLJX0uKhbrew==",
+ "7Y87wVJok20UfuwkGbXxLg==",
+ "ibsb1ncaLZXAYgGkMO7tjQ==",
+ "+VfRcTBQ80KSeJRdg0cDfw==",
+ "kgKWQJJQKLUuD2VYKIKvxA==",
+ "ARKIvf4+zRF8eCvUITWPng==",
+ "1fztTtQWNMIMSAc5Hr6jMQ==",
+ "md6zNd7ZBn3qArYqQz7/fw==",
+ "kvAaIJb+aRAfKK104dxFAA==",
+ "UIXytIHyVODxlrg+eQoARA==",
+ "Dk0L/lQizPEb3Qud6VHb1Q==",
+ "64YsV2qeDxk2Q6WK/h7OqA==",
+ "90dtIMq0ozJXezT2r79vMQ==",
+ "wy/Z8505o4sVovk4UuBp1A==",
+ "ytDXLDBqWiU1w3sTurYmaw==",
+ "9pk75mBzhmcdT+koHvgDlw==",
+ "DQeib845UqBMEl96sqsaSg==",
+ "UPYR575ASaBSZIR3aX1IgQ==",
+ "swsVVsPi/5aPFBGP+jmPIw==",
+ "1cj1Fpd3+UiBAOahEhsluA==",
+ "ifuJCv9ZA84Vz1FYAPsyEA==",
+ "uu+ncs63SdQIvG6z4r7Q3Q==",
+ "UvC1WADanMrhT+gPp/yVqA==",
+ "llOvGOUDVfX68jKnAlvVRA==",
+ "SusSOsWNoAerAIMBVWHtfA==",
+ "VznvTPAAwAev+yhl9oZT0w==",
+ "luR/kvHLwA6tSdLeTM4TzA==",
+ "PcdBtV8pfKU0YbDpsjPgwg==",
+ "5l6kDfjtZjkTZPJvNNOVFw==",
+ "4FBBtWPvqJ3dv4w25tRHiQ==",
+ "JJbzQ/trOeqQomsKXKwUpQ==",
+ "0bj069wXgEJbw7dpiPr8Tg==",
+ "tejpAZp7y32SO2+o4OGvwQ==",
+ "kq26VyDyJTH/eM6QvS2cMw==",
+ "+zBkeHF4P8vLzk1iO1Zn3Q==",
+ "BzkNYH03gF/mQY71RwO3VA==",
+ "RnxOYPSQdHS6fw4KkDJtrA==",
+ "65KhGKUBFQubRRIEdh9SwQ==",
+ "k1DPiH6NkOFXP/r3N12GyA==",
+ "DqzWt1gfyu/e7RQl5zWnuQ==",
+ "gnez1VrH+UHT8C/SB9qGdA==",
+ "vZtL0yWpSIA+9v8i23bZSg==",
+ "FNvQqYoe0s/SogpAB7Hr1Q==",
+ "6nwR+e9Qw0qp8qIwH9S/Mg==",
+ "BPT4PQxeQcsZsUQl33VGmg==",
+ "rOYeIcB+Rg5V6JG2k4zS2w==",
+ "Je1UESovkBa9T6wS0hevLw==",
+ "HFHMGgfOeO0UPrray1G+Zw==",
+ "NBmB/cQfS+ipERd7j9+oVg==",
+ "iIm8c9uDotr87Aij+4vnMw==",
+ "S3VQa6DH+BdlSrxT/g6B5g==",
+ "BwRA+tMtwEvth28IwpZx+w==",
+ "vg3jozLXEmAnmJwdfcEN0g==",
+ "gW0oKhtQQ7BxozxUWw5XvQ==",
+ "Q6vGRQiNwoyz7bDETGvi5g==",
+ "Ak3rlzEOds6ykivfg39xmw==",
+ "G4qzBI1sFP2faN+tlRL/Bw==",
+ "ND9l4JWcncRaSLATsq0LVw==",
+ "yQmNZnp/JZywbBiZs3gecA==",
+ "ZoNSxARrRiKZF5Wvpg7bew==",
+ "GhpJfRSWZigLg/azTssyVA==",
+ "QyyiJ5I/OZC50o89fa5EmQ==",
+ "4kj0S8XlmhHXoUP7dQItUw==",
+ "Dt8Q5ORzTmpPR2Wdk0k+Aw==",
+ "/hFhjFGJx2wRfz6hyrIpvA==",
+ "eFimq+LuHi42byKnBeqnZQ==",
+ "JrKGKAKdjfAaYeQH8Y2ZRQ==",
+ "JFFeXsFsMA59iNtZey7LAA==",
+ "91SdBFJEZ65M+ixGaprY/A==",
+ "+S+WXgVDSU1oGmCzGwuT3g==",
+ "1X14kHeKwGmLeYqpe60XEA==",
+ "4xojeUxTFmMLGm6jiMYh/Q==",
+ "+1e7jvUo8f2/2l0TFrQqfA==",
+ "8WU1vLKV1GhrL7oS9PpABg==",
+ "DYWCPUq/hpjr6puBE7KBHg==",
+ "birqO8GOwGEI97zYaHyAuw==",
+ "6e8boFcyc8iF0/tHVje4eQ==",
+ "FLvED9nB9FEl9LqPn7OOrA==",
+ "ji306HRiq965zb8EZD2uig==",
+ "AklOdt9/2//3ylUhWebHRw==",
+ "VGRCSrgGTkBNb8sve0fYnQ==",
+ "oqlkgrYe9aCOwHXddxuyag==",
+ "KXuFON8tMBizNkCC48ICLA==",
+ "9aKH1u5+4lgYhhLztQ4KWA==",
+ "3hVslsq98QCDIiO40JNOuA==",
+ "OOS6wQCJsXH8CsWEidB35A==",
+ "YXHQ3JI9+oca8pc/jMH6mA==",
+ "V9vkAanK+Pkc4FGAokJsTA==",
+ "OFLn4wun6lq484I7f6yEwg==",
+ "3WVBP9fyAiBPZAq3DpMwOQ==",
+ "5gGoDPTc/sOIDLngmlEq4A==",
+ "E2lvMXqHdTw0x+KCKVnblg==",
+ "f1Gs++Iilgq9GHukcnBG3w==",
+ "uIkVijg7RPi/1j7c18G1qA==",
+ "9T7gB0ZkdWB0VpbKIXiujQ==",
+ "KCJJfgLe00+tjSfP6EBcUg==",
+ "WbAdlac/PhYUq7J2+n5f+w==",
+ "GLnS9wDCje7TOMvBX9jJVA==",
+ "VAg/aU5nl72O+cdNuPRO4g==",
+ "kzTl7WH/JXsX1fqgnuTOgw==",
+ "1HDgfU7xU7LWO/BXsODZAQ==",
+ "D0W5F7gKMljoG5rlue1jrg==",
+ "9reBKZ1Rp6xcdH1pFQacjw==",
+ "SSKhl2L3Mvy93DcZulADtA==",
+ "hlu7os0KtAkpBTBV6D2jyQ==",
+ "sfte/o9vVNyida/yLvqADA==",
+ "gYGQBLo5TdMyXks0LsZhsQ==",
+ "dNq2InSVDGnYXjkxPNPRxA==",
+ "fiv0DJivQeqUkrzDNlluRw==",
+ "msstzxq++XO0AqNTmA7Bmg==",
+ "DCjgaGV5hgSVtFY5tcwkuA==",
+ "aMmrAzoRWLOMPHhBuxczKg==",
+ "qNOSm15bdkIDSc/iUr+UTQ==",
+ "2nSTEYzLK77h5Rgyti+ULQ==",
+ "BhKO1s1O693Fjy1LItR/Jw==",
+ "kRnBEH6ILR5GNSmjHYOclw==",
+ "R97chlspND/sE9/HMScXjQ==",
+ "1Oykse0jQVbuR3MvW5ot4A==",
+ "Dmyb+a7/QFsU4d2cVQsxDw==",
+ "W5now3RWSzzMDAxsHSl++Q==",
+ "IrDuBrVu1HWm0BthAHyOLQ==",
+ "V6zyoX6MERIybGhhULnZiw==",
+ "ZQSDYgpsimK+lYGdXBWE/w==",
+ "lV70RNlE++04G1KFB3BMXA==",
+ "QmSBVvdk0tqH9RAicXq2zA==",
+ "qNyy6Fc0b8oOMWqqaliZ/w==",
+ "xvipmmwKdYt4eoKvvRnjEg==",
+ "Q7Df6zGwvb4rC+EtIKfaSw==",
+ "n1M2dgFPpmaICP+JwxHUug==",
+ "1k8tL2xmGFVYMgKUcmDcEw==",
+ "fFvXa1dbMoOOoWZdHxPGjw==",
+ "UP9mmAKzeQqGhod7NCqzhg==",
+ "PMCWKgog/G+GFZcIruSONw==",
+ "dnvatwSEcl73ROwcZ4bbIQ==",
+ "hY82j+sUQQRpCi6CCGea5A==",
+ "QoUC9nyK1BAzoUVnBLV2zw==",
+ "+aF4ilbjQbLpAuFXQEYMWQ==",
+ "XTCcsVfEvqxnjc0K5PLcyw==",
+ "ML7ipnY/g8mA1PUIju1j8Q==",
+ "tOkYq1BZY152/7IJ6ZYKUg==",
+ "2bsIpvnGcFhTCSrK9EW1FQ==",
+ "Af9j1naGtnZf0u1LyYmK1w==",
+ "ZmblZauRqO5tGysY3/0kDw==",
+ "PF0lpolQQXlpc3qTLMBk8w==",
+ "emVLJVzha7ui5OFHPJzeRQ==",
+ "gR0sgItXIH8hE4FVs9Q07w==",
+ "PTW+fhZq/ErxHqpM0DZwHQ==",
+ "g0kHTNRI7x/lAsr92EEppw==",
+ "24H9q+E8pgCEdFS7JO5kzQ==",
+ "HtDXgMuF8PJ1haWk88S0Ew==",
+ "pulldyBt2sw6QDvTrCh6zw==",
+ "ehwc2vvwNUAI7MxU4MWQZw==",
+ "enj9VEzLbmeOyYugTmdGfQ==",
+ "auvG6kWMnhCMi7c7e9eHrw==",
+ "R36O31Pj8jn0AWSuqI7X2Q==",
+ "3AVYtcIv7A5mVbVnQMaCeA==",
+ "T9WoUJNwp8h4Yydixbx6nA==",
+ "t0WN8TwMLgi8UVEImoFXKg==",
+ "mS99D+CXhwyfVt8xJ+dJZA==",
+ "AFdelaqvxRj6T3YdLgCFyg==",
+ "Lu02ic/E94s42A14m7NGCA==",
+ "7w3b73nN/fIBvuLuGZDCYQ==",
+ "O209ftgvu0vSr0UZywRFXA==",
+ "MQvAr+OOfnYnr/Il/2Ubkg==",
+ "e5txnNRcGs2a9+mBFcF1Qg==",
+ "YA0kMTJ82PYuLA4pkn4rfw==",
+ "QIKjir/ppRyS63BwUcHWmw==",
+ "P3y5MoXrkRTSLhCdLlnc4A==",
+ "WY7mCUGvpXrC8gkBB46euw==",
+ "g0GbRp2hFVIdc7ct7Ky7ag==",
+ "Cv079ZF55RnbsDT27MOQIA==",
+ "cvMJ714elj/HUh89a9lzOQ==",
+ "9inw7xzbqAnZDKOl/MfCqA==",
+ "F58ktE4O0f7C9HdsXYm+lw==",
+ "CsPkyTZADMnKcgSuNu1qxg==",
+ "mAzsVkijuqihhmhNTTz65g==",
+ "FxnbKnuDct4OWcnFMT/a5w==",
+ "P5wS+xB8srW4a5KDp/JVkA==",
+ "ctJYJegZhG42i+vnPFWAWw==",
+ "OrqJKjRndcZ8OjE3cSQv7g==",
+ "aXqiibI6BpW3qilV6izHaQ==",
+ "BA18GEAOOyVXO2yZt2U35w==",
+ "saEpnDGBSZWqeXSJm34eOA==",
+ "CUEueo8QXRxkfVdfNIk/gg==",
+ "H0UMAUfHFQH92A2AXRCBKA==",
+ "CT9g8mKsIN/VeHLSTFJcNQ==",
+ "E4NtzxQruLcetC23zKVIng==",
+ "203EqmJI9Q4tWxTJaBdSzA==",
+ "Do3aqbRKtmlQI2fXtSZfxQ==",
+ "JaYQXntiyznQzrTlEeZMIw==",
+ "VK95g27ws2C6J2h/7rC2qA==",
+ "CQ0PPwgdG3N6Ohfwx1C8xA==",
+ "/MeHciFhvFzQsCIw39xIZA==",
+ "u5cUPxM6/spLIV8VidPrAA==",
+ "OwArFF1hpdBupCkanpwT+Q==",
+ "PdBgXFq5mBqNxgCiqaRnkw==",
+ "lC5EumoIcctvxYqwELqIqw==",
+ "xoPSM86Se+1hHX0y3hhdkw==",
+ "F5bs0GGWBx9eBwcJJpXbqg==",
+ "1mw6LfTiirFyfjejf8QNGA==",
+ "daBhAvmE9shDgmciDAC5eg==",
+ "AvdeYb9XNOUFWiiz+XGfng==",
+ "JJJkp1TpuDx5wrua2Wml7g==",
+ "3y5Xk65ShGvWFbQxcZaQAQ==",
+ "l6QHU5JsJExNoOnqxBPVbw==",
+ "X2YfnPXgF2VHVX95ZcBaxQ==",
+ "g6udffWh7qUnSIo1Ldn3eA==",
+ "V2P75JFB4Se9h7TCUMfeNA==",
+ "IUZ5aGpkJ9rLgSg6oAmMlw==",
+ "pyrUqiZ98gVXxlXQNXv5fA==",
+ "83ERX2XJV3ST4XwvN7YWCg==",
+ "eJDUejE/Ez/7kV+S74PDYg==",
+ "M9oqlPb63e0kZE0zWOm+JQ==",
+ "0rTYcuVYdilO7zEfKrxY3A==",
+ "rfPTskbnoh3hRJH6ZAzQRg==",
+ "QtD35QhE8sAccPrDnhtQmQ==",
+ "jpNUgFnanr9Sxvj2xbBXZw==",
+ "nykEOLL/o7h0cs0yvdeT2g==",
+ "wX2URK6eDDHeEOF3cgPgHA==",
+ "jqPQ0aOuvOJte/ghI1RVng==",
+ "nHTsDl0xeQPC5zNRnoa0Rw==",
+ "mNv2Q67zePjk/jbQuvkAFA==",
+ "HjlPM2FQWdILUXHalIhQ5w==",
+ "cHkOsVd80Rgwepeweq4S1g==",
+ "kTCHqcb3Cos51o8cL+MXcg==",
+ "nvmBgp0YlUrdZ05INsEE8Q==",
+ "kFrRjz7Cf2KvLtz9X6oD+w==",
+ "Tmx0suRHzlUK4FdBivwOwA==",
+ "bG+P+p34t/IJ1ubRiWg6IA==",
+ "uESeJe/nYrHCq4RQbrNpGA==",
+ "ehfPlu6YctzzpQmFiQDxGA==",
+ "ZH5Es/4lJ+D5KEkF1BVSGg==",
+ "HHxn4iIQ7m0tF1rSd+BZBg==",
+ "DQJRsUwO1fOuGlkgJavcwQ==",
+ "HITIVoFoWNg04NExe13dNA==",
+ "MeKXnEfxeuQu9t3r/qWvcw==",
+ "Y7OofF9eUvp7qlpgdrzvkg==",
+ "XSb71ae0v+yDxNF5HJXGbQ==",
+ "p8W1LgFuW6JSOKjHkx3+aA==",
+ "y2JOIoIiT9cV1VxplZPraQ==",
+ "MN94B0r5CNAF9sl3Kccdbw==",
+ "Q1pdQadt12anX1QRmU2Y/A==",
+ "JIC8R48jGVqro6wmG2KXIw==",
+ "eWgLAqJOU+fdn8raHb9HCw==",
+ "5CMadLqS2KWwwMCpzlDmLw==",
+ "H1y2iXVaQYwP0SakN6sa+Q==",
+ "CUCjG2UaEBmiYWQc6+AS1Q==",
+ "yV3IbbTWAbHMhMGVvgb/ZQ==",
+ "80PCwYh4llIKAplcDvMj4g==",
+ "fgdUFvQPb5h+Rqz8pzLsmw==",
+ "2SI4F7Vvde2yjzMLAwxOog==",
+ "kJdY3XEdJS/hyHdR+IN0GA==",
+ "IKgNa2oPaFVGYnOsL+GC5Q==",
+ "eXFOya6x5inTdGwJx/xtUQ==",
+ "uTA0XbiH3fTeVV7u5z0b3w==",
+ "onFcHOO1c3pDdfCb5N4WkQ==",
+ "Slu3z535ijcs5kzDnR7kfA==",
+ "SElc2+YVi3afE1eG1MI7dQ==",
+ "ND2hYtAIQGMxBF7o7+u7nQ==",
+ "Pv9FWQEDLKnG/9K9EIz4Gw==",
+ "6CjtF1S2Y6RCbhl7hMsD+g==",
+ "rs2QrN4qzAHCHhkcrAvIfA==",
+ "eTMPXa60OTGjSPmvR4IgGw==",
+ "pvXHwJ3dwf9GDzfDD9JI3g==",
+ "CRmAj3JcasAb4iZ9ZbNIbw==",
+ "rcY4Ot40678ByCfqvGOGdg==",
+ "l4ddTxbTCW5UmZW+KRmx6A==",
+ "NKRzJndo2uXNiNppVnqy1g==",
+ "0NrvBuyjcJ2q6yaHpz/FOA==",
+ "3YXp1PmMldUjBz3hC6ItbA==",
+ "CmVD6nh8b/04/6JV9SovlA==",
+ "HjyxyL0db2hGDq2ZjwOOhg==",
+ "4PBaoeEwUj79njftnYYqLg==",
+ "vFFzkWgGyw6OPADONtEojQ==",
+ "czBWiYsQtNFrksWwoQxlOw==",
+ "9iB7+VwXRbi6HLkWyh9/kg==",
+ "zwY6tCjjya/bgrYaCncaag==",
+ "mW6TCje9Zg2Ep7nzmDjSYQ==",
+ "5LJqHFRyIwQKA4HbtqAYQQ==",
+ "INNBBin5ePwTyhPIyndHHg==",
+ "dChBe9QR29ObPFu/9PusLg==",
+ "1dhq3ozNCx0o4dV1syLVDA==",
+ "nyaekSYTKzfSeSfPrB114Q==",
+ "TfNHjSTV8w6Pg6+FaGlxvA==",
+ "m/Lp4U75AQyk9c8cX14HJg==",
+ "uU1TX5DoDg6EcFKgFcn0GA==",
+ "B+TsxQZf0IiQrU8X9S4dsQ==",
+ "6b7ue29cBDsvmj1VSa5njw==",
+ "RvXWAFwM+mUAPW1MjPBaHA==",
+ "pdaY6kZ8+QqkMOInvvACNA==",
+ "7nr3zyWL+HHtJhRrCPhYZA==",
+ "BXGlq54wIH6R3OdYfSSDRw==",
+ "b06KGv5zDYsTxyTbQ9/eyA==",
+ "8ylI1AS3QJpAi3I/NLMYdg==",
+ "0fpe9E6m3eLp/5j5rLrz2Q==",
+ "Qrh7OEHjp80IW+YzQwzlJg==",
+ "lqhgbgEqROAdfzEnJ17eXA==",
+ "Dulw855DfgIwiK7hr3X8vg==",
+ "wsp+vmW8sEqXYVURd/gjHA==",
+ "VoPth5hDHhkQcrQTxHXbuw==",
+ "TgWe70YalDPyyUz6n88ujg==",
+ "9lLhHcrPWI4EsA4fHIIXuw==",
+ "UymZUnEEQWVnLDdRemv+Tw==",
+ "qnkFUlJ8QT322JuCI3LQgg==",
+ "/p/aCTIhi1bU0/liuO/a2Q==",
+ "hWoxz5HhE50oYBNRoPp1JQ==",
+ "88tB/HgUIUnqWXEX++b5Aw==",
+ "Z8T1b9RsUWf59D06MUrXCQ==",
+ "BZTzHJGhzhs3mCXHDqMjnQ==",
+ "XfY+QUriCAA1+3QAsswdgg==",
+ "TZ3ATPOFjNqFGSKY3vP2Hw==",
+ "cl4t9FXabQg7tbh1g7a0OA==",
+ "9SgfpAY0UhNC6sYGus9GgQ==",
+ "d/Wd3Ma1xYyoMByPQnA9Cw==",
+ "DDitrRSvovaiXe2nfAtp4g==",
+ "s+eHg5K9zZ2Jozu5Oya9ZQ==",
+ "z3L2BNjQOMOfTVBUxcpnRA==",
+ "v4xIYrfPGILEbD/LwVDDzA==",
+ "HoaBBw2aPCyhh0f5GxF+/Q==",
+ "i9IRqAqKjBTppsxtPB7rdw==",
+ "cWUg7AfqhiiEmBIu+ryImA==",
+ "E+02smwQGBIxv42LIF2Y4Q==",
+ "W4CfeVp9mXgk04flryL7iA==",
+ "9SUOfKtfKmkGICJnvbIDMg==",
+ "xweGAZf+Yb3TtwR/sGmGIA==",
+ "EJgedRYsZPc4cT9rlwaZhg==",
+ "wv4NC9CIpwuGf/nOQYe/oA==",
+ "ZXeMG5eqQpZO/SGKC4WQkA==",
+ "bzXXzQGZs8ustv0K4leklA==",
+ "RkQK9S1ezo+dFYHQP57qrw==",
+ "mrinv7KooPQPrLCNTRWCFg==",
+ "qIUJPanWmGzTD1XxvHp+6w==",
+ "Js7g8Dr6XsnGURA4UNF0Ug==",
+ "dpSTNOCPFHN5yGoMpl1EUA==",
+ "ugY8rTtJkN4CXWMVcRZiZw==",
+ "rqHKB91H3qVuQAm+Ym5cUA==",
+ "UjmDFO7uzjl4RZDPeMeNyg==",
+ "cu4ZluwohhfIYLkWp72pqA==",
+ "ZydKlOpn2ySBW0G3uAqwuw==",
+ "LWd0+N3M94n81qd346LfJQ==",
+ "VbHoWmtiiPdABvkbt+3XKQ==",
+ "J4MC9He6oqjOWsYQh9nl3Q==",
+ "ahAbmGJZvUOXrcK6OydNGQ==",
+ "Byhi4ymFqqH8uIeoMRvPug==",
+ "LSN9GmT6LUHlCAMFqpuPIA==",
+ "IAMInfSYb76GxDlAr1dsTg==",
+ "qYHdgFAXhF/XcW4lxqfvWQ==",
+ "26+yXbqI+fmIZsYl4UhUzw==",
+ "AwPTZpC28NJQhf5fNiJuLA==",
+ "SESKbGF35rjO64gktmLTWA==",
+ "YVlRQHQglkbj3J2nHiP/Hw==",
+ "DdaT4JLC7U0EkF50LzIj9w==",
+ "G0LChrb0OE5YFqsfTpIL1Q==",
+ "5Yrj6uevT8wHRyqqgnSfeg==",
+ "NmWmDxwK5FpKlZbo0Rt8RA==",
+ "iUsUCB0mfRsE9KPEQctIzw==",
+ "Tm4zk2Lmg8w4ITMI31NfTA==",
+ "Vu0E+IJXBnc25x4n41kQig==",
+ "6wkfN8hyKmKU6tG3YetCmw==",
+ "trjM81KANPZrg9iSThWx6Q==",
+ "iGuY4VxcotHvMFXuXum7KA==",
+ "ICPdBCdONUqPwD5BXU5lrw==",
+ "alqHQBz8V446EdzuVfeY5Q==",
+ "74FW/QYTzr/P1k6QwVHMcw==",
+ "avZp5K7zJvRvJvpLSldNAw==",
+ "TIKadc6FAaRWSQUg5OATgg==",
+ "PfkWkSbAxIt1Iso0znW0+Q==",
+ "Z+bsbVP91KrJvxrujBLrrQ==",
+ "mrxlFD3FBqpSZr1kuuwxGg==",
+ "nUgYO7/oVNSX8fJqP2dbdg==",
+ "tVhXk9Ff3wAg56FbdNtcFg==",
+ "DdiNGiOSoIZxrMrGNvqkXw==",
+ "CDsanJz7e3r/eQe+ZYFeVQ==",
+ "wVfSZYjMjbTsD2gaSbwuqQ==",
+ "6c0iuya20Ys8BsvoI4iQaQ==",
+ "qCPfJTR8ecTw6u6b1yHibA==",
+ "fZrj3wGQSt8RXv0ykJROcQ==",
+ "gR3B8usSEb0NLos51BmJQg==",
+ "vTAmgfq3GxL4+ubXpzwk5w==",
+ "jLkmUZ6fV56GfhC0nkh4GA==",
+ "3v09RHCPTLUztqapThYaHg==",
+ "nULSbtw2dXbfVjZh33pDiA==",
+ "IHhyR6+5sZXTH+/NrghIPg==",
+ "tnUtJ/DQX9WaVJyTgemsUA==",
+ "7xTKFcog69nTmMfr5qFUTA==",
+ "IshzWega6zr3979khNVFQQ==",
+ "Ng5v/B9Z10TTfsDFQ/XrXQ==",
+ "hnCUnoxofUiqQvrxl73M8w==",
+ "VPa7DG6v7KnzMvtJPb88LQ==",
+ "4LtQrahKXVtsbXrEzYU1zQ==",
+ "Ev/xjTi7akYBI7IeZJ4Igw==",
+ "41WEjhYUlG6jp2UPGj11eQ==",
+ "JvXTdChcE3AqMbFYTT3/wg==",
+ "2rOkEVl90EPqfHOF5q2FYw==",
+ "mjFBVRJ7TgnJx+Q74xllPg==",
+ "Uy4QI8D2y1bq/HDNItCtAw==",
+ "wMOE/pEKVIklE75xjt6b6w==",
+ "ZcuIvc8fDI+2uF0I0uLiVA==",
+ "CX/N/lHckmAtHKysYtGdZA==",
+ "j8to4gtSIRYpCogv2TESuQ==",
+ "iS9wumBV5ktCTefFzKYfkA==",
+ "ewPT4dM12nDWEDoRfiZZnA==",
+ "vWn9OPnrJgfPavg4D6T/HQ==",
+ "J/PNYu4y6ZMWFFXsAhaoow==",
+ "catI+QUNk3uJ+mUBY3bY8Q==",
+ "F8tEIT5EhcvLNRU5f0zlXQ==",
+ "zyA9f5J7mw5InjhcfeumAQ==",
+ "MlOOZOwcRGIkifaktEq0aQ==",
+ "Pt3i49uweYVgWze3OjkjJA==",
+ "sfIClgTMtZo9CM9MHaoqhQ==",
+ "HeQbUuBM9sqfXFXRBDISSw==",
+ "SFn78uklZfMtKoz2N0xDaQ==",
+ "H6j2nPbBaxHecXruxiWYkA==",
+ "fU32wmMeD44UsFSqFY0wBA==",
+ "hDILjSpTLqJpiSSSGu445A==",
+ "ieEAgvK9LsWh2t6DsQOpWA==",
+ "xfjBQk3CrNjhufdPIhr91A==",
+ "j+8/VARfbQSYhHzj0KPurQ==",
+ "/zFLRvi75UL8qvg+a6zqGg==",
+ "U0KmEI6e5zJkaI4YJyA5Ew==",
+ "uXvr6vi5kazZ9BCg2PWPJA==",
+ "jEqP0dyHKHiUjZ9dNNGTlQ==",
+ "1xWx5V3G9murZP7srljFmA==",
+ "OIwtfdq37eQ0qoXuB2j7Hw==",
+ "fUAy3f9bAglLvZWvkO2Lug==",
+ "duRFqmvqF93uf/vWn8aOmg==",
+ "ysRQ+7Aq7eVLOp88KnFVMA==",
+ "CkZUmKBAGu0FLpgPDrybpw==",
+ "TrLmfgwaNATh24eSrOT+pw==",
+ "83wtvSoSP9FVBsdWaiWfpA==",
+ "pUfWmRXo70yGkUD/x5oIvA==",
+ "PybPZhJErbRTuAafrrkb3g==",
+ "8hsfXqi4uiuL+bV1VrHqCw==",
+ "TVlHoi8J7sOZ2Ti7Dm92cQ==",
+ "za4rzveYVMFe3Gw531DQJQ==",
+ "JKphO0UYjFqcbPr6EeBuqg==",
+ "hqeSvwu8eqA072iidlJBAw==",
+ "bUF0JIfS4uKd3JZj2xotLQ==",
+ "hKOsXOBoFTl/K4xE+RNHDA==",
+ "JHBjKpCgSgrNNACZW1W+1w==",
+ "Rrq0ak9YexLqqbSD4SSXlw==",
+ "+NmjwjsPhGJh9bM10SFkLw==",
+ "xMIHeno2qj3V8q9H1xezeg==",
+ "TcFinyBrUoAEcLzWdFymow==",
+ "Rvchz/xjcY9uKiDAkRBMmA==",
+ "TYlnrwgyeZoRgOpBYneRAg==",
+ "PbnxuVerGwHyshkumqAARg==",
+ "iFtadcw8v6betKka9yaJfg==",
+ "7wgT9WIiMVcrj48PVAMIgw==",
+ "2HHqeGRMfzf3RXwVybx+ZQ==",
+ "tdgI9v7cqJsgCAeW1Fii1A==",
+ "4ZFYKa7ZgvHyZLS6WpM8gA==",
+ "gB8wkuIzvuDAIhDtNT1gyA==",
+ "g1ELwsk6hQ+RAY1BH640Pg==",
+ "UZoibx+y1YJy/uRSa9Oa2w==",
+ "yS/yMnJDHW0iaOsbj4oPTg==",
+ "JzW+yhrjXW1ivKu3mUXPXg==",
+ "/wIZAye9h1TUiZmDW0ZmYA==",
+ "YK+q7uJObkQZvOwQ9hplMg==",
+ "Rs8deApkoosIJSfX7NXtAA==",
+ "MsCloSmTFoBpm7XWYb+ueQ==",
+ "3ltw31yJuAl4VT6MieEXXw==",
+ "1+qmrbC8c7MJ6pxmDMcKuA==",
+ "AYxGETZs477n2sa1Ulu/RQ==",
+ "Q0TJZxpn3jk67L7N+YDaNA==",
+ "OGpsXRHlaN8BvZftxh1e7A==",
+ "UbABE6ECnjB+9YvblE9CYw==",
+ "kZ0D191c/uv4YMG15yVLDw==",
+ "QWURrsEgxbJ8MWcaRmOWqw==",
+ "xiFlcSfa/gnPiO+LwbixcQ==",
+ "Szko0IPE7RX2+mfsWczrMg==",
+ "Ugt8HVC/aUzyWpiHd0gCOQ==",
+ "8j9GVPiFdfIRm/+ho7hpoA==",
+ "KR401XBdgCrtVDSaXqPEiA==",
+ "d0NBFiwGlQNclKObRtGVMQ==",
+ "XEwOJG24eaEtAuBWtMxhwg==",
+ "0Y6iiZjCwPDwD/CwJzfioQ==",
+ "MvMbvZNKbXFe2XdN+HtnpQ==",
+ "fsoXIbq0T0nmSpW8b+bj+g==",
+ "Uje3Ild84sN41JEg3PEHDg==",
+ "i6ZYpFwsyWyMJNgqUMSV1A==",
+ "+P5q4YD1Rr5SX26Xr+tzlw==",
+ "z4oKy2wKH+sbNSgGjbdHGw==",
+ "XwKWd03sAz8MmvJEuN08xA==",
+ "Xv0mNYedaBc57RrcbHr9OA==",
+ "9oUawSwUGOmb0sDn3XS6og==",
+ "9RGIQ2qyevNbSSEF36xk/A==",
+ "q8YF9G2jqydAxSqwyyys5Q==",
+ "m5JIUETVXcRza4VL4xlJbg==",
+ "aRpdnrOyu5mWB1P5YMbvOA==",
+ "rM/BOovNgnvebKMxZQdk7g==",
+ "fQS0jnQMnHBn7+JZWkiE/g==",
+ "gAoV4BZYdW1Wm712YXOhWQ==",
+ "hCzsi1yDv9ja5/o7t94j9Q==",
+ "CoLvjQDQGldGDqRxfQo+WQ==",
+ "pfGcaa49SM3S6yJIPk/EJQ==",
+ "yYp4iuI5f/y/l1AEJxYolQ==",
+ "Jj4IrSVpqQnhFrzNvylSzA==",
+ "4jeOFKuKpCmMXUVJSh9y0g==",
+ "+NMUaQ7XPsAi0rk7tTT9wQ==",
+ "Jt4Eg6MJn8O4Ph/K2LeSUA==",
+ "CiiUeJ0LeWfm7+gmEmYXtg==",
+ "c5Tc7rTFXNJqYyc0ppW+Iw==",
+ "4KJZPCE9NKTfzFxl76GWjg==",
+ "aXs9qTEXLTkN956ch3pnOA==",
+ "f5Xo7F1uaiM760Qbt978iw==",
+ "wpZqFkKafFpLcykN2IISqg==",
+ "vIORTYSHFIXk5E2NyIvWcQ==",
+ "prOsOG0adI4o+oz50moipw==",
+ "blygTgAHZJ3NzyAT33Bfww==",
+ "rBt6L/KLT7eybxKt5wtFdg==",
+ "vMuaLvAntJB5o7lmt/kVXA==",
+ "iujlt9fXcUXEYc+T2s5UjA==",
+ "LyYPOZKm8bBegMr5NTSBfg==",
+ "ZtWvgitOSRDWq7LAKYYd4Q==",
+ "kh51WUI5TRnKhur6ZEpRTQ==",
+ "VzQ1NwNv9btxUzxwVqvHQg==",
+ "8fJLQeIHaTnJ8wGqUiKU6g==",
+ "vvEH5A39TTe1AOC11rRCLA==",
+ "dihDsG7+6aocG6M9BWrCzQ==",
+ "3jqsY8/xTWELmu/az3Daug==",
+ "mpOtwBvle+nyY6lUBwTemw==",
+ "E1CvxFbuu9AYW604mnpGTw==",
+ "1LPC0BzhJbepHTSAiZ3QTw==",
+ "XpGXh76RDgXC4qnTCsnNHA==",
+ "3Gg9N7vjAfQEYOtQKuF/Eg==",
+ "+WpF8+poKmHPUBB4UYh/ig==",
+ "UNt7CNMtltJWq8giDciGyA==",
+ "RIZYDgXqsIdTf9o2Tp/S7g==",
+ "0QCQORCYfLuSbq94Sbt0bQ==",
+ "hvsZ5JmVevK1zclFYmxHaw==",
+ "3+9nURtBK3FKn0J9DQDa3g==",
+ "jdVMQqApseHH3fd91NFhxg==",
+ "VX+cVXV8p9i5EBTMoiQOQQ==",
+ "I5qDndyelK4Njv4YrX7S6w==",
+ "rWliqgfZ3/uCRBOZ9sMmdA==",
+ "vwno3vugCvt6ooT3CD4qIQ==",
+ "cffrYrBX3UQhfX1TbAF+GQ==",
+ "nOiwBFnXxCBfPCHYITgqNg==",
+ "LQttmX92SI94+hDNVd8Gtw==",
+ "iCF+GWw9/YGQXsOOPAnPHQ==",
+ "nwtCsN1xEYaHvEOPzBv+qQ==",
+ "CQpJFrpOvcQhsTXIlJli+Q==",
+ "tYeIZjIm0tVEsYxH1iIiUQ==",
+ "iCnm5fPmSmxsIzuRK6osrA==",
+ "tX8X8KoxUQ8atFSCxgwE1Q==",
+ "hZlX6qOfwxW5SPfqtRqaMw==",
+ "2aIx9UdMxxZWvrfeJ+DcTw==",
+ "TlJizlASbPtShZhkPww4UA==",
+ "p+bx+/WQWALXEBCTnIMr4w==",
+ "4VR5LiXLew6Nyn91zH9L4w==",
+ "bfUD03N2PRDT+MZ+WFVtow==",
+ "cTvDd8okNUx0RCMer6O8sw==",
+ "49jZr/mEW6fvnyzskyN40w==",
+ "vHmQUl4WHXs1E/Shh+TeyA==",
+ "fgXfRuqFfAu8qxbTi4bmhA==",
+ "Wn+Vj4eiWx0WPUHr3nFbyA==",
+ "2SwIiUwT4vRZPrg7+vZqDA==",
+ "nkedTagkmf6YE4tEY+0fKw==",
+ "8nOTDhFyZ8YUA4b6M5p84w==",
+ "qnzWszsyJhYtx8wkMN6b1g==",
+ "ka7pMp8eSiv92WgAsz2vdA==",
+ "pGQEWJ38hb/ZYy2P1+FIuw==",
+ "cVhdRFuZaW/09CYPmtNv5g==",
+ "prCOYlboBnzmLEBG/OeVrQ==",
+ "oIWwTbkVS5DDL47mY9/1KQ==",
+ "PKtXc4x4DEjM45dnmPWzyg==",
+ "f9ywiGXsz+PuEsLTV3zIbQ==",
+ "6G2bD3Y7qbGmfPqH9TqLFA==",
+ "DMHmyn2U2n+UXxkqdvKpnA==",
+ "XOG1PYgqoG8gVLIbVLTQgg==",
+ "1FSrgkUXgZot2CsmbAtkPw==",
+ "BxFP+4o6PSlGN78eSVT1pA==",
+ "EZVQGsXTZvht1qedRLF8bQ==",
+ "eYAQWuWZX2346VMCD6s7/A==",
+ "jkUpkLoIXuu7aSH8ZghIAQ==",
+ "mXPtbPaoNAAlGmUMmJEWBQ==",
+ "HLesnV3DL+FhWF3h6RXe8g==",
+ "nDAsSla+9XfAlQSPsXtzPA==",
+ "RAECgYZmcF4WxcFcZ4A0Ww==",
+ "W+M4BcYNmjj7xAximDGWsA==",
+ "ueODvMv/f9ZD8O0aIHn4sg==",
+ "cszpMdGbsbe6BygqMlnC9Q==",
+ "siHwJx6EgeB1gBT9z/vTyw==",
+ "FN7oLGBQGHXXn5dLnr/ElA==",
+ "Tud+AMyuFkWYYZ73yoJGpQ==",
+ "TuaG3wRdM9BWKAxh2UmAsg==",
+ "8CjmgWQSAAGcXX9kz3kssw==",
+ "ays5/F7JANIgPHN0vp2dqQ==",
+ "PCOGl7GIqbizAKj/sZmlwQ==",
+ "rZKD8oJnIj5fSNGiccfcvA==",
+ "gFEnTI8os2BfRGqx9p5x8w==",
+ "5r1ZsGkrzNQEpgt/gENibw==",
+ "1YO9G8qAhLIu2rShvekedw==",
+ "6ZKmm7IW7IdWuVytLr68CQ==",
+ "mMfn8OaKBxtetweulho+xQ==",
+ "GQJxu1SoMBH14KPV/G/KrQ==",
+ "IYIP2UBRyWetVfYLRsi1SQ==",
+ "Jit0X0srSNFnn8Ymi1EY+g==",
+ "ARCWkHAnVgBOIkCDQ19ZuA==",
+ "qA0sTaeNPNIiQbjIe1bOgQ==",
+ "iGI9uqMoBBAjPszpxjZBWQ==",
+ "+L1FDsr5VQtuYc2Is5QGjw==",
+ "4XNUmgwxsqDYsNmPkgNQYQ==",
+ "Yig+Wh18VIqdsmwtwfoUQw==",
+ "uqp92lAqjec8UQYfyjaEZw==",
+ "QiozlNcQCbqXtwItWExqJQ==",
+ "JFHutgSe1/SlcYKIbNNYwQ==",
+ "Y26jxXvl79RcffH8O8b9Ew==",
+ "bQ7J5mebp38rfP/fuqQOsg==",
+ "HI4ZIE5s8ez8Rb+Mv39FxA==",
+ "OzH7jTcyeM7RPVFtBdakpQ==",
+ "HLxROy6fx/mLXFTDSX4eLA==",
+ "s5RUHVRNAoKMuPR/Jkfc2Q==",
+ "X9QAaNjgiOeAWSphrGtyVw==",
+ "ALJWKUImVE40MbEooqsrng==",
+ "9MDG0WeBPpjGJLEmUJgBWg==",
+ "9RXymE9kCkDvBzWGyMgIWA==",
+ "vFox1d3llOeBeCUZGvTy0A==",
+ "r3lQAYOYhwlLnDWQIunKqg==",
+ "2os5s7j7Tl46ZmoZJH8FjA==",
+ "O5N2yd+QQggPBinQ+zIhtQ==",
+ "ZygAjaN62XhW5smlLkks+Q==",
+ "AgDJsaW0LkpGE65Kxk5+IA==",
+ "omAjyj1l6gyQAlBGfdxJTw==",
+ "fY9VATklOvceDfHZDDk57A==",
+ "StpQm/cQF8cT0LFzKUhC5w==",
+ "CYJB3qy5GalPLAv1KGFEZA==",
+ "coGEgMVs2b314qrXMjNumQ==",
+ "DQQB/l55iPN9XcySieNX3A==",
+ "6dshA8knH5qqD+KmR/kdSQ==",
+ "qyRmvxh8p4j4f+61c10ZFQ==",
+ "apWEPWUvMC24Y+2vTSLXoA==",
+ "RzX2OfSFEd//LhZwRwzBVw==",
+ "NdULoUDGhIolzw1PyYKV0A==",
+ "5w/c9WkI/FA+4lOtdPxoww==",
+ "bV9r7j2kNJpDCEM5E2339Q==",
+ "vbyiKeDCQ4q9dDRI1Q0Ong==",
+ "9xIgKpZGqq0/OU6wM5ZSHw==",
+ "RYkDwwng6eeffPHxt8iD9A==",
+ "w5N/aHbtOIKzcvG3GlMjGA==",
+ "3P2aJxV8Trll2GH9ptElYA==",
+ "yteeQr3ub2lDXgLziZV+DQ==",
+ "yqtj8GfLaUHYv/BsdjxIVw==",
+ "NyF+4VRog7etp90B9FuEjA==",
+ "uwA6N5LptSXqIBkTO0Jd7Q==",
+ "6lVSzYUQ/r0ep4W2eCzFpg==",
+ "1d7RPHdZ9qzAbG3Vi9BdFA==",
+ "7br49X11xc2GxQLSpZWjKQ==",
+ "peMW+rpwmXrSwplVuB/gTA==",
+ "RqYpA5AY7mKPaSxoQfI1CA==",
+ "dqVw2q2nhCvTcW82MT7z0g==",
+ "5S5/asYfWjOwnzYpbK6JDw==",
+ "NvkR0inSzAdetpI4SOXGhw==",
+ "tIqwBotg052wGBL65DZ+yA==",
+ "S4RvORcJ3m6WhnAgV4YfYA==",
+ "UAqf4owQ+EmrE45hBcUMEw==",
+ "4aPU6053cfMLHgLwAZJRNg==",
+ "3Y6/HqS1trYc9Dh778sefg==",
+ "ck86G8HsbXflyrK7MBntLg==",
+ "GLmWLXURlUOJ+PMjpWEXVA==",
+ "jNJQ6otieHBYIXA9LjXprg==",
+ "AsAHrIkMgc3RRWnklY9lJw==",
+ "FCLQocqxxhJeleARZ6kSPg==",
+ "3Leu2Sc+YOntJFlrvhaXeg==",
+ "hSkY45CeB6Ilvh0Io4W6cg==",
+ "DwrNdmU5VFFf3TwCCcptPA==",
+ "u2WQlcMxOACy6VbJXK4FwA==",
+ "E9IlDyULLdeaVUzN6eky8g==",
+ "EXveRXjzsjh8zbbQY2pM9g==",
+ "5VO1inwXMvLDBQSOahT6rg==",
+ "HaHTsLzx7V3G1SFknXpGxA==",
+ "MMaegl2Md9s/wOx5o9564w==",
+ "mpWNaUH9kn4WY26DWNAh3Q==",
+ "w3G+qXXqqKi8F5s+qvkBUg==",
+ "wM8tnXO4PDlLVHspZFcjYw==",
+ "LFcpCtnSnsCPD2gT/RA+Zg==",
+ "bhVbgJ4Do4v56D9mBuR/EA==",
+ "yU3N0HMSP5etuHPNrVkZtg==",
+ "FzqIpOcTsckSNHExrl+9jg==",
+ "BYz52gYI/Z6AbYbjWefcEA==",
+ "h3vYYI9yhpSZV2MQMJtwFQ==",
+ "adJAjAFyR2ne1puEgRiH+g==",
+ "eDcyiPaB954q5cPXcuxAQw==",
+ "40gCrW4YWi+2lkqMSPKBPg==",
+ "ulLuTZqhEDkX0EJ3xwRP9A==",
+ "y4iBxAMn/KzMmaWShdYiIw==",
+ "ilBBNK/IV69xKTShvI94fQ==",
+ "0HN6MIGtkdzNPsrGs611xA==",
+ "twPn6wTGqI0aR//0wP3xtA==",
+ "3UNJ37f+gnNyYk9yLFeoYA==",
+ "4SdHWowXgCpCDL28jEFpAw==",
+ "Mr5mCtC53+wwmwujOU/fWw==",
+ "81pAhreEPxcKse+++h1qBg==",
+ "KmcGEE0pacQ/HDUgjlt7Pg==",
+ "Gt4/MMrLBErhbFjGbiNqQQ==",
+ "lf1fwA0YoWUZaEybE+LyMQ==",
+ "RIVYGO2smx9rmRoDVYMPXw==",
+ "rJ9qVn8/2nOxexWzqIHlcQ==",
+ "lfOLLyZNbsWQgHRhicr4ag==",
+ "wgH1GlUxWi6/yLLFzE76uQ==",
+ "Qg1ubGl+orphvT990e5ZPA==",
+ "Z5B+uOmPZbpbFWHpI9WhPw==",
+ "snGTzo540cCqgBjxrfNpKw==",
+ "ZqkmoGB0p5uT5J6XBGh7Tw==",
+ "uPi8TsGY3vQsMVo/nsbgVQ==",
+ "Y5XR8Igvau/h+c1pRgKayg==",
+ "ZmVpw1TUVuT13Zw/MNI5hQ==",
+ "60suecbWRfexSh7C67RENA==",
+ "kZ/mZZg9YSDmk2rCGChYAg==",
+ "OpL+vHwPasW30s2E1TYgpA==",
+ "ZVnErH1Si4u51QoT0OT7pA==",
+ "3pi3aNVq1QNJmu1j0iyL0g==",
+ "tb5+2dmYALJibez1W4zXgA==",
+ "jOPdd330tB6+7C29a9wn0Q==",
+ "5oD/aGqoakxaezq43x0Tvw==",
+ "HdB7Se47cWjPgpJN0pZuiA==",
+ "6WhHPWlqEUqXC52rHGRHjA==",
+ "WLwpjgr9KzevuogoHZaVUw==",
+ "E8yMPK7W0SIGTK6gIqhxiQ==",
+ "1/Hxu8M9N/oNwk8bCj4FNQ==",
+ "Uo1ebgsOxc3eDRds1ah3ag==",
+ "5pqqzC/YmRIMA9tMFPi7rg==",
+ "ri4AOITPdB1YHyXV+5S51g==",
+ "HfvsiCQN/3mT0FabCU5ygQ==",
+ "UQTQk5rrs6lEb1a+nkLwfg==",
+ "VH70dN82yPCRctmAHMfCig==",
+ "yD3Dd4ToRrl53k/2NSCJiw==",
+ "fO0+6TsjL+45p9mSsMRiIg==",
+ "fM5uYpkvJFArnYiQ3MrQnA==",
+ "V+QzdKh5gxTPp2yPC9ZNEg==",
+ "XHHEg/8KZioW/4/wgSEkbQ==",
+ "2abfl3N46tznOpr+94VONQ==",
+ "gxwbqZDHLbQVqXjaq42BCg==",
+ "WnHK5ZQDR6Da5cGODXeo0A==",
+ "SChDh/Np1HyTPWfICfE1uA==",
+ "yhexr/OFKfZl0o3lS70e4w==",
+ "N65PqIWiQeS082D6qpfrAg==",
+ "RM5CpIiB94Sqxi462G7caA==",
+ "CBAGa5l95f3hVzNi6MPWeQ==",
+ "OHJBT2SEv5b5NxBpiAf7oQ==",
+ "p48i7AfSSAyTdJSyHvOONw==",
+ "/SP6pOdYFzcAl2OL05z4uQ==",
+ "N8dXCawxSBX40fgRRSDqlQ==",
+ "bMWFvjM8eVezU1ZXKmdgqw==",
+ "Um1ftRBycvb+363a90Osog==",
+ "QAz7FA+jpz9GgLvwdoNTEQ==",
+ "qO4HlyHMK5ygX+6HbwQe8w==",
+ "UgvtdE2eBZBUCAJG/6c0og==",
+ "q5g3c8tnQTW2EjNfb2sukw==",
+ "gsC/mWD8KFblxB0JxNuqJw==",
+ "SVFbcjXbV7HRg+7jUrzpwg==",
+ "bz294kSG4egZnH2dJ8HwEg==",
+ "ybpTgPr3SjJ12Rj5lC/IMA==",
+ "yDrAd1ot38soBk7zKdnT8A==",
+ "BB/R8oQOcoE4j63Hrh8ifg==",
+ "GNrMvNXQkW7PydlyJa+f1w==",
+ "w0PKdssv+Zc5J/BbphoxpA==",
+ "D5ibbo8UJMfFZ48RffuhgQ==",
+ "MdvhC1cuXqni/0mtQlSOCw==",
+ "wQKL8Ga6JQkpZ7yymDkC3w==",
+ "o1uhaQg5/zfne84BFAINUQ==",
+ "Ft2wXUokFdUf6d2Y/lwriw==",
+ "sLJrshdEANp0qk2xOUtTnQ==",
+ "jx7rpxbm1NaUMcE2ktg5sA==",
+ "ZQ0ZnTsZKWxbRj7Tilh24Q==",
+ "KhrIIHfqXl9zGE9aGrkRVg==",
+ "jS0JuioLGAVaHdo/96JFoQ==",
+ "tr+U/vt+MIGXPRQYYWJfRg==",
+ "TXab/hqNGWaSK+fXAoB2bg==",
+ "0K4NBxqEa3RYpnrkrD/XjQ==",
+ "3oMTbWf7Bv83KRlfjNWQZA==",
+ "yLAhLNezvqVHmN1SfMRrPw==",
+ "ZYW30FfgwHmW6nAbUGmwzA==",
+ "CZNoTy26VUQirvYxSPc/5A==",
+ "CF1sAlhjDQY/KWOBnSSveA==",
+ "+CLf5witKkuOvPCulTlkqw==",
+ "1m1yD4L9A7Q1Ot+wCsrxJQ==",
+ "2E41e0MgM3WhFx2oasIQeA==",
+ "mDXHuOmI4ayjy2kLSHku1Q==",
+ "sCLMrLjEUQ6P1L8tz90Kxg==",
+ "zDUZCzQesFjO1JI3PwDjfg==",
+ "x/BIDm6TKMhqu/gtb3kGyw==",
+ "DEaZD/8aWV6+zkiLSVN/gA==",
+ "7dz+W494zwU5sg63v5flCg==",
+ "Y5iDQySR2c3MK7RPMCgSrw==",
+ "GglPoW5fvr4JSM3Zv99oiA==",
+ "myzvc+2MfxGD9uuvZYdnqQ==",
+ "V9G1we3DOIQGKXjjPqIppQ==",
+ "gYvdNJCDDQmNhtJ6NKSuTA==",
+ "rXtGpN17Onx8LnccJnXwJQ==",
+ "/a+bLXOq02sa/s8h7PhUTg==",
+ "htNVAogFakQkTX6GHoCVXg==",
+ "eshD40tvOA6bXb0Fs/cH3A==",
+ "K1CGbMfhlhIuS0YHLG30PQ==",
+ "aOeJZUIZM9YWjIEokFPnzQ==",
+ "r0hAwlS0mPZVfCSB+2G6uQ==",
+ "0q+erphtrB+6HBnnYg7O6w==",
+ "bkRdUHAksJZGzE1gugizYQ==",
+ "J8v2f6hWFu8oLuwhOeoQjA==",
+ "qkvEep4vvXhc2ZJ6R449Mg==",
+ "6HGeEPyTAu9oiKhNVLjQnA==",
+ "JoATsk/aJH0UcDchFMksWA==",
+ "QozQL0DTtr+PXNKifv6l6g==",
+ "HiAgt86AyznvbI2pnLalVQ==",
+ "lY+tivtsfvU0LJzBQ6itYQ==",
+ "EfXDc6h69aBPE6qsB+6+Ig==",
+ "gnAIpoCyl3mQytLFgBEgGA==",
+ "p2JPOX8yDQ0agG+tUyyT/g==",
+ "zeELfk015D5krExLKRUYtg==",
+ "wDiGoFEfIVEDyyc4VpwhWQ==",
+ "7Ephy+mklG2Y3MFdqmXqlA==",
+ "8ZFPMJJYVJHsfRpU4DigSg==",
+ "ocRh5LR1ZIN9Johnht8fhQ==",
+ "l5f3I6osM9oxLRAwnUnc5A==",
+ "yxCyBXqGWA735JEyljDP7Q==",
+ "qE/h/Z+6buZWf+cmPdhxog==",
+ "HCu4ZMrcLMZbPXbTlWuvvQ==",
+ "TDrq23VUdzEU/8L5i8jRJQ==",
+ "L+N/6geuokiLPPSDXM9Qkg==",
+ "v6jZicMNM3ysm3U5xu0HoQ==",
+ "b85nxzs8xiHxaqezuDVWvg==",
+ "ca+kx+kf7JuZ3pfYKDwFlg==",
+ "KlY5TGg0pR/57TVX+ik1KQ==",
+ "3jmCreW5ytSuGfmeLv7NfQ==",
+ "ucLMWnNDSqE4NOCGWvcGWw==",
+ "NSrzwNlB0bde3ph8k6ZQcQ==",
+ "nL4iEd3b5v4Y9fHWDs+Lrw==",
+ "W2x0SBzSIsTRgyWUCOZ/lg==",
+ "ifZM0gBm9g9L09YlL+vXBg==",
+ "4WcFEswYU/HHQPw77DYnyA==",
+ "TLJbasOoVO435E5NE5JDcA==",
+ "WyCFB4+6lVtlzu3ExHAGbQ==",
+ "BW0A06zoQw7S+YMGaegT7g==",
+ "qP1cCE4zsKGTPhjbcpczMw==",
+ "UVEZPoH9cysC+17MKHFraw==",
+ "eQ45Mvf5in9xKrP6/qjYbg==",
+ "fOARCnIg/foF/6tm7m9+3w==",
+ "lK2xe+OuPutp4os0ZAZx5w==",
+ "Tug3eh+28ttyf+U7jfpg5w==",
+ "ENFfP93LA257G6pXQkmIdg==",
+ "FuWspiqu5g8Eeli5Az+BkA==",
+ "kIGxCUxSlNgsKZ45Al1lWw==",
+ "RzeH+G3gvuK1z+nJGYqARQ==",
+ "0ofMbUCA3/v5L8lHnX4S5w==",
+ "VI8pgqBZeGWNaxkuqQVe7g==",
+ "x6lNRGgJcRxgKTlzhc1WPg==",
+ "La0gzdbDyXUq6YAXeKPuJA==",
+ "dAq8/1JSQf1f4QPLUitp0g==",
+ "WN7lFJfw4lSnTCcbmt5nsg==",
+ "2aDK0tGNgMLyxT+BQPDE8Q==",
+ "9W57pTzc572EvSURqwrRhw==",
+ "37Nkh06O979nt7xzspOFyQ==",
+ "4TQkMnRsXBobbtnBmfPKnA==",
+ "f/BjtP5fmFw2dRHgocbFlg==",
+ "9vEgJVJLEfed6wJ7hBUGgQ==",
+ "HRWYX2XOdsOqYzCcqkwIyw==",
+ "StDtLMlCI75g4XC59mESEQ==",
+ "99+SBN45LwKCPfrjUKRPmw==",
+ "HbT6W1Ssd3W7ApKzrmsbcg==",
+ "l8/KMItWaW3n4g1Yot/rcQ==",
+ "s7iW1M6gkAMp+D/3jHY58w==",
+ "GWwJ32SZqD5wldrXUdNTLA==",
+ "YhLEPsi/TNyeUJw69SPYzQ==",
+ "g0aTR8aJ0uVy3YvGYu5xrw==",
+ "m6get5wjq5j1i5abnpXuZQ==",
+ "ymtA8EMPMgmMcimWZZ0A1Q==",
+ "HEcOaEd9zCoOVbEmroSvJg==",
+ "F8l+Qd9TZgzV+r8G584lKA==",
+ "3yDD+xT8iRfUVdxcc7RxKw==",
+ "1eRUCdIJe3YGD5jOMbkkOg==",
+ "DO1/jfP/xBI9N0RJNqB2Rw==",
+ "SiSlasZ+6U2IZYogqr2UPg==",
+ "tBQDfy48FnIOZI04rxfdcA==",
+ "HEghmKg3GN60K7otpeNhaA==",
+ "mTLBkP+yGHsdk5g7zLjVUw==",
+ "RgtwfY5pTolKrUGT+6Pp6g==",
+ "EyIsYQxgFa4huyo/Lomv7g==",
+ "HwLSUie8bzH+pOJT3XQFyg==",
+ "7Tauesu7bgs5lJmQROVFiQ==",
+ "ojugpLIfzflgU2lonfdGxA==",
+ "ZqjnqxZE/BjOUY0CMdVl0g==",
+ "oQjugfjraFziga1BcwRLRA==",
+ "JXCYeWjFqcdSf6QwB54G+A==",
+ "TeBGJCqSqbzvljIh9viAqA==",
+ "1Gpj4TPXhdPEI4zfQFsOCg==",
+ "asouSfUjJa8yfMG7BBe+fA==",
+ "ccy3Ke2k4+evIw0agHlh3w==",
+ "CzSumIcYrZlxOUwUnLR2Zw==",
+ "9QFYrCXsGsInUb4SClS3cQ==",
+ "3RTtSaMp1TZegJo5gFtwwA==",
+ "aTWiWjyeSDVY/q8y9xc2zg==",
+ "UK+R+hAoVeZ4xvsoZjdWpw==",
+ "rHagXw+CkF3uEWPWDKXvog==",
+ "MfkyURTBfkNZwB+wZKjP4g==",
+ "Qf7JFJJuuacSzl6djUT2EQ==",
+ "K1RL+tLjICBvMupe7QppIQ==",
+ "R2OOV18CV/YpWL1xzr/VQg==",
+ "o+areESiXgSO0Lby56cBeg==",
+ "VPqyIomYm7HbK5biVDvlpw==",
+ "pw1jplCdTC+b0ThX0FXOjw==",
+ "gTnsH3IzALFscTZ1JkA9pw==",
+ "JYJvOZ4CHktLrYJyAbdOnA==",
+ "P8lUiLFoL100c9YSQWYqDA==",
+ "LATQEY7f47i77M6p11wjWA==",
+ "U9kE50Wq5/EHO03c5hE4Ug==",
+ "pFKzcRHSUBqSMtkEJvrR1Q==",
+ "vHVXsAMQqc0qp7HA5Q+YkA==",
+ "3XyoREdvhmSbyvAbgw2y/A==",
+ "qOEIUWtGm5vx/+fg4tuazg==",
+ "a6IszND1m+6w+W+CvseC7g==",
+ "KuNY8qAJBce+yUIluW8AYw==",
+ "5Wcq+6hgnWsQZ/bojERpUw==",
+ "l2ZB9TvT68rn8AAN4MdxWw==",
+ "h5HsEsObPuPFqREfynVblw==",
+ "fvm0IQfnbfZFETg9v3z/Fg==",
+ "QV0OG5bpjrjku4AzDvp9yw==",
+ "nMuMtK/Zkb3Xr34oFuX/Lg==",
+ "jMZKSMP2THqwpWqJNJRWdw==",
+ "fX4G68hFL7DmEmjbWlCBJQ==",
+ "ZlBNHAiYsfaEEiPQ1z+rCA==",
+ "ckugAisBNX18eQz+EnEjjw==",
+ "Dt6hvhPJu94CJpiyJ5uUkg==",
+ "eYE9No9sN5kUZ5ePEyS3+Q==",
+ "Tp52d1NndiC9w3crFqFm9g==",
+ "MBjMU/17AXBK0tqyARZP5w==",
+ "1EI9aa955ejNo1dJepcZJw==",
+ "FqWLkhWl0iiD/u2cp+XK9A==",
+ "j8nMH8mK/0Aae7ZkqyPgdg==",
+ "ZtmnX24AwYAXHb2ZDC6MeQ==",
+ "who8uUamlHWHXnBf7dwy4A==",
+ "CmkmWcMK4eqPBcRbdnQvhw==",
+ "61V74uIjaSfZM8au1dxr1A==",
+ "778O1hdVKHLG2q9dycUS0Q==",
+ "IdadoCPmSgHDHzn1zyf8Jw==",
+ "Z2rwGmVEMCY6nCfHO3qOzw==",
+ "Q3TpCE+wnmH/1h/EPWsBtQ==",
+ "HnVfyqgJ+1xSsN4deTXcIA==",
+ "XgPHx2+ULpm14IOZU2lrDg==",
+ "IbN736G1Px5bsYqE5gW1JQ==",
+ "nY/H7vThZ+dDxoPRyql+Cg==",
+ "wlWxtQDJ+siGhN2fJn3qtw==",
+ "MrbEUlTagbesBNg0OemHpw==",
+ "LJtRcR70ug6UHiuqbT6NGw==",
+ "hSNZWNKUtDtMo6otkXA/DA==",
+ "LawT9ZygiVtBk0XJ+KkQgQ==",
+ "DLzHkTjjuH6LpWHo2ITD0Q==",
+ "i8XXN7jcrmhnrOVDV8a2Hw==",
+ "ogcuGHUZJkmv+vCz567a2g==",
+ "rUp5Mfc57+A8Q29SPcvH/Q==",
+ "6706ncrH1OANFnaK6DUMqQ==",
+ "gK7dhke5ChQzlYc/bcIkcg==",
+ "t3Txxjq43e/CtQmfQTKwWg==",
+ "6ZMs9vCzK9lsbS6eyzZlIA==",
+ "uTHBqApdKOAgdwX3cjrCYQ==",
+ "zirOtGUXeRL22ezfotZfQg==",
+ "iK0dWKHjVVexuXvMWJV9pg==",
+ "uzEgwx1iAXAvWPKSVwYSeQ==",
+ "FHvI0IVNvih8tC7JgzvCOw==",
+ "jjNMPXbmpFNsCpWY0cv3eg==",
+ "/cJ0Nn5YbXeUpOHMfWXNHQ==",
+ "WkSJpxBa45XJRWWZFee7hw==",
+ "edlXkskLx287vOBZ9+gVYg==",
+ "+Pl0bSMBAdXpRIA+zE02JA==",
+ "3xw8+0/WU51Yz4TWIMK8mw==",
+ "GdTanUprpE3X/YjJDPpkhQ==",
+ "qnsBdl050y9cUaWxbCczRw==",
+ "pnJnBzAJlO4j3IRqcfmhkQ==",
+ "USq1iF90eUv41QBebs3bhw==",
+ "QH3lAwOYBAJ0Fd5pULAZqw==",
+ "gvvyX5ATi4q9NhnwxRxC8w==",
+ "7xDIG/80SnhgxAYPL9YJtg==",
+ "WVhfn2yJZ43qCTu0TVWJwA==",
+ "twjiDKJM7528oIu/el4Zbg==",
+ "6sBemZt4qY/TBwqk3YcLOQ==",
+ "m3XYojKO+I6PXlVRUQBC3w==",
+ "gUNP5w7ANJm257qjFxSJrA==",
+ "mMLhjdWNnZ8zts9q+a2v3g==",
+ "kjWYVC7Eok2w2YT4rrI+IA==",
+ "ZzT5b0dYQXkQHTXySpWEaA==",
+ "YzTV0esAxBFVls3e0qRsnA==",
+ "9xmtuClkFlpz/X5E9JBWBA==",
+ "nhAnHuCGXcYlqzOxrrEe1g==",
+ "cbBXgB1WQ/i8Xul0bYY2fg==",
+ "AkAes5oErTaJiGD2I4A1Pw==",
+ "Wx9jh/teM0LJHrvTScssyQ==",
+ "fU5ZZ1bIVsV+eXxOpGWo/Q==",
+ "k8eZxqwxiN/ievXdLSEL/w==",
+ "E2LR1aZ3DcdCBuVT7BhReA==",
+ "1eCHcz4swFH+uRhiilOinQ==",
+ "JipruVZx4ban3Zo5nNM37g==",
+ "IPLD9nT5EEYG9ioaSIYuuA==",
+ "pHozgRyMiEmyzThtJnY4MQ==",
+ "p0eNK7zJd7D/HEGaVOrtrQ==",
+ "dGjcKAOGBd4gIjJq7fL+qQ==",
+ "uMq8cDVWFD+tpn8aeP8Pqg==",
+ "gC7gUwGumN7GNlWwfIOjJQ==",
+ "It+K/RCYMOfNrDZxo7lbcA==",
+ "4CfEP8TeMKX33ktwgifGgA==",
+ "nxDGRpePV3H4NChn4eLwag==",
+ "300hoYyMR/mk1mfWJxS8/w==",
+ "DmxgZsQg+Qy1GP0fPkW3VA==",
+ "1vqRt79ukuvdJNyIlIag8Q==",
+ "RWI0HfpP7643OSEZR8kxzw==",
+ "zZtYkKU50PPEj6qSbO5/Sw==",
+ "UNRlg6+CYVOt68NwgufGNA==",
+ "kkbX+a00dfiTgbMI+aJpMg==",
+ "VIC7inSiqzM6v9VqtXDyCw==",
+ "l+x2QhxG8wb5AQbcRxXlmA==",
+ "GUiinC3vgBjbQC2ybMrMNQ==",
+ "6uMF5i0b/xsk55DlPumT7A==",
+ "aK9nybtiIBUvxgs1iQFgsw==",
+ "BLbTFLSb4mkxMaq4/B2khg==",
+ "mTAqtg6oi0iytHQCaSVUsA==",
+ "eBapvE+hdyFTsZ0y5yrahg==",
+ "lHN2dn2cUKJ8ocVL3vEhUQ==",
+ "Mj87ajJ/yR41XwAbFzJbcA==",
+ "FA+nK6mpFWdD0kLFcEdhxA==",
+ "FrTgaF5YZCNkyfR1kVzTLQ==",
+ "5eHStFN7wEmIE+uuRwIlPQ==",
+ "AyWlT+EGzIXc395zTlEU5Q==",
+ "I+wVQA+jpPTJ6xEsAlYucg==",
+ "Y1flEyZZAYxauMo4cmtJ1w==",
+ "1AeReq55UQotRQVKJ66pmg==",
+ "xzGzN5Hhbh0m/KezjNvXbQ==",
+ "meHzY9dIF7llDpFQo1gyMg==",
+ "RnOXOygwJFqrD+DlM3R5Ew==",
+ "JKg64m6mU7C/CkTwVn4ASg==",
+ "gGLz3Ss+amU7y6JF09jq7A==",
+ "Pu9pEf+Tek3J+3jmQNqrKw==",
+ "EATnlYm0p3h04cLAL95JgA==",
+ "o64LDtKq/Fulf1PkVfFcyg==",
+ "hUWqqG1QwYgGC5uXJpCvJw==",
+ "RfSwpO/ywQx4lfgeYlBr2w==",
+ "VaJc9vtYlqJbRPGb5Tf0ow==",
+ "9JKIJrlQjhNSC46H3Cstcw==",
+ "6Z9myGCF5ylWljgIYAmhqw==",
+ "9bAWYElyRN1oJ6eJwPtCtQ==",
+ "ohK6EftXOqBzIMI+5XnESw==",
+ "AVjwqrTBQH1VREuBlOyUOg==",
+ "G2UponGde3/Z+9b2m9abpQ==",
+ "DoiItHSms0B9gYmunVbRkQ==",
+ "vUC0HlTTHj6qNHwfviDtAw==",
+ "hq35Fjgvrcx6I9e6egWS4w==",
+ "sw+bmpzqsM4gEQtnqocQLQ==",
+ "ApiuEPWr8UjuRyJjsYZQBw==",
+ "VXu4ARjq7DS2IR/gT24Pfw==",
+ "3TbRZtFtsh9ez8hqZuTDeA==",
+ "CazLJMJjQMeHhYLwXW7YNg==",
+ "ROSt+NlEoiPFtpRqKtDUrQ==",
+ "IUwVHH6+8/0c+nOrjclOWA==",
+ "lkzFdvtBx5bV6xZO0cxK7g==",
+ "4ekt4m38G9m599xJCmhlug==",
+ "fzkmVWKhJsxyCwiqB/ULnQ==",
+ "LZAKplVoNjeQgfaHqkyEJA==",
+ "91vfsZ7Lx9x5gqWTOdM4sg==",
+ "MVoxyIA+emaulH8Oks8Weg==",
+ "oGH7SMLI2/qjd9Vnhi3s0A==",
+ "vmqfGJE6r4yDahtU/HLrxw==",
+ "Y5KKN7t/v9JSxG/m1GMPSA==",
+ "gXlb7bbRqHXusTE5deolGA==",
+ "/2c4oNniwhL3z5IOngfggg==",
+ "HgIFX42oUdRPu7sKAXhNWg==",
+ "A3dX2ShyL9+WOi6MNJBoYQ==",
+ "hN9bmMHfmnVBVr+7Ibd2Ng==",
+ "DB706G73NpBSRS8TKQOVZw==",
+ "JSyq2MIuObPnEgEUDyALjQ==",
+ "kSUectNPXpXNg+tIveTFRw==",
+ "XVVy3e6dTnO3HpgD6BtwQw==",
+ "td7nDgTDmKPSODRusMcupw==",
+ "Lt/pVD4TFRoiikmgAxEWEw==",
+ "mmRob7iyTkTLDu8ObmTPow==",
+ "Fd0c8f2eykUp9GYhqOcKoA==",
+ "18RKixTv12q3xoBLz6eKiA==",
+ "RClzwwKh51rbB4ekl99EZA==",
+ "oONlXCW4aAqGczQ/bUllBw==",
+ "foPAmiABJ3IXBoed2EgQXA==",
+ "wEJDulZafLuXCvcqBYioFQ==",
+ "K1RgR6HR5uDEQgZ32TAFgA==",
+ "SEIZhyguLoyH7So0p1KY0A==",
+ "ggIfX1J4dX3xQoHnHUI7VA==",
+ "HBRzLacCVYfwUVGzrefZYg==",
+ "aWZRql2IUPVe9hS3dxgVfQ==",
+ "Err1mbWJud80JNsDEmXcYg==",
+ "Z2MkqmpQXdlctCTCUDPyzw==",
+ "JnE6BK0vpWIhNkaeaYNUzw==",
+ "5dUry23poD+0wxZ3hH6WmA==",
+ "DwP0MQf71VsqvAbAMtC3QQ==",
+ "kHcBZXoxnFJ+GMwBZ/xhfQ==",
+ "SUAwMWLMml8uGqagz5oqhQ==",
+ "79uTykH43voFC3XhHHUzKg==",
+ "P5fucOJhtcRIoElFJS4ffg==",
+ "s8NpalwgPdHPla7Zi9FJ3w==",
+ "8cXqZub6rjgJXmh1CYJBOg==",
+ "tY916jrSySzrL+YTcVmYKQ==",
+ "DRiFNojs7wM8sfkWcmLnhQ==",
+ "wqUJ1Gq1Yz2cXFkbcCmzHQ==",
+ "0u+0WHr7WI6IlVBBgiRi6w==",
+ "GCYI9Dn1h3gOuueKc7pdKA==",
+ "nVDxVhaa2o38gd1XJgE3aw==",
+ "5I/heFSQG/UpWGx0uhAqGQ==",
+ "1PvTn90xwZJPoVfyT5/uIQ==",
+ "jHOoSl3ldFYr9YErEBnD3w==",
+ "swJhrPwllq5JORWiP5EkDA==",
+ "tj2rWvF2Fl+XIccctj8Mhw==",
+ "QvYZxsLdu+3nV/WhY1DsYg==",
+ "fKalNdhsyxTt1w08bv9fJA==",
+ "CHLHizLruvCrVi9chj9sXA==",
+ "sa2DECaqYH1z1/AFhpHi+g==",
+ "LbPp1oL0t3K2BAlIN+l8DA==",
+ "5SbwLDNT6sBOy6nONtUcTg==",
+ "AfVPdxD3FyfwwNrQnVNQ7A==",
+ "jt9Ocr9D8EwGRgrXVz//aQ==",
+ "KkwQL0DeUM3nPFfHb2ej+A==",
+ "WwraoO97OTalvavjUsqhxQ==",
+ "fAKFfwlCOyhtdBK6yNnsNg==",
+ "EqMlrz1to7HG4GIFTPaehQ==",
+ "YmjZJyNfHN5FaTL/HAm8ww==",
+ "L2D7G0btrwxl9V4dP3XM5Q==",
+ "oUqO4HrBvkpSL781qAC9+w==",
+ "c6Yhwy/q3j7skXq52l36Ww==",
+ "FWphIPZMumqnXr1glnbK4w==",
+ "AcKwfS8FRVqb72uSkDNY/Q==",
+ "uSIiF1r9F18avZczmlEuMQ==",
+ "XrFDomoH2qFjQ2jJ2yp9lA==",
+ "N2X7KWekNN+fMmwyXgKD5w==",
+ "IdmcpJXyVDajzeiGZixhSA==",
+ "Wf2olJCYZRGTTZxZoBePuQ==",
+ "oVlG+0rjrg2tdFImxIeVBA==",
+ "7w4PDRJxptG8HMe/ijL6cQ==",
+ "rueNryrchijjmWaA3kljYg==",
+ "ZybIEGf1Rn/26vlHmuMxhw==",
+ "yYVW07lOZHdgtX42xJONIA==",
+ "4ifNsmjYf1iOn2YpMfzihg==",
+ "KTjwL+qswa+Bid8xLdjMTg==",
+ "THfzE2G2NVKKfO+A2TjeFw==",
+ "QoqHzpHDHTwQD5UF30NruQ==",
+ "dTMoNd6DDr1Tu8tuZWLudw==",
+ "wOc4TbwQGUwOC1B3BEZ4OQ==",
+ "gfhkPuMvjoC3CGcnOvki3Q==",
+ "vljJciS+uuIvL7XXm5688g==",
+ "EGLOaMe6Nvzs/cmb7pNpbg==",
+ "oLWWIn/2AbKRHnddr2og9g==",
+ "7l0RMKbONGS/goW/M+gnMQ==",
+ "eFkXKRd2dwu/KWI5ZFpEzw==",
+ "jWsC7kdp2YmIZpfXGUimiA==",
+ "Jcxjli2tcIAjCe+5LyvqdQ==",
+ "MUkRa/PjeWMhbCTq43g6Aw==",
+ "g2nh2xENCFOpHZfdEXnoQA==",
+ "x6M66krXSi0EhppwmDmsxA==",
+ "26Wmdp6SkKN74W0/XPcnmA==",
+ "ycjv4XkS5O7zcF3sqq9MwQ==",
+ "gfnbviaVhKvv1UvlRGznww==",
+ "aIPde9CtyZrhbHLK740bfw==",
+ "0p8YbEMxeb73HbAfvPLQRw==",
+ "Is3uxoSNqoIo5I15z6Z2UQ==",
+ "NZtcY8fIpSKPso/KA6ZfzA==",
+ "iQ304I1hmLZktA1d1cuOJA==",
+ "0QB0OUW5x2JLHfrtmpZQ+w==",
+ "kgyUtd8MFe0tuuxDEUZA9w==",
+ "AcbG0e6xN8pZfYAv7QJe1Q==",
+ "bb/U8UynPHwczew/hxLQxw==",
+ "NuBYjwlxadAH+vLWYRZ3bg==",
+ "Ao1Zc0h5AdSHtYt1caWZnQ==",
+ "FL/j3GJBuXdAo54JYiWklQ==",
+ "E2v8Kk60qVpQ232YzjS2ow==",
+ "zVupSPz7cD0v/mD/eUIIjg==",
+ "sEeblUmISi1HK4omrWuPTA==",
+ "xQpYjaAmrQudWgsdu24J0A==",
+ "vCekQ2nOQKiN/q8Be/qwZg==",
+ "8g08gjG/QtvAYer32xgNAg==",
+ "miiOqnhtef1ODjFzMHnxjA==",
+ "sXlFMSTBFnq0STHj6cS/8w==",
+ "+SclwwY8R2RPrnX54Z+A6w==",
+ "g8TcogVxHpw7uhgNFt5VCQ==",
+ "9viAzLFGYYudBYFu7kFamg==",
+ "BAJ+/jbk2HyobezZyB9LiQ==",
+ "/DJgKE9ouibewuZ2QEnk6w==",
+ "fxg/vQq9WPpmQsqQ4RFYaA==",
+ "lM/EhwTsbivA7MDecaVTPw==",
+ "pVgjGg4TeTNhKimyOu3AAw==",
+ "gYnznEt9r97haD/j2Cko7g==",
+ "/ngbFuKIAVpdSwsA3VxvNw==",
+ "VCL3xfPVCL5RjihQM59fgg==",
+ "eDWsx4isnr2xPveBOGc7Hw==",
+ "FIOCTEbzb2+KMCnEdJ7jZw==",
+ "40HzgVKYnqIb6NJhpSIF0A==",
+ "ccK42Lm8Tsv73YMVZRwL6A==",
+ "MpAwWMt7bcs4eL7hCSLudQ==",
+ "zxsSqovedB3HT99jVblCnQ==",
+ "4erEA42TqGA9K4iFKkxMMA==",
+ "BaRwTrc5ulyKbW4+QqD0dw==",
+ "CT3ldhWpS1SEEmPtjejR/Q==",
+ "lkl6XkrTMUpXi46dPxTPxg==",
+ "3EhLkC9NqD3A6ApV6idmgg==",
+ "fsW2DaKYTCC7gswCT+ByQQ==",
+ "pW4gDKtVLj48gNz6V17QdA==",
+ "KjfL7YyVqmCJGBGDFdJ0gw==",
+ "bGGUhiG9SqJMHQWitXTcYQ==",
+ "8RtLlzkGEiisy1v9Xo0sbw==",
+ "R81DX/5a7DYKkS4CU+TL+w==",
+ "Tu6w6DtX2RJJ3Ym3o3QAWw==",
+ "nx/U4Tode5ILux4DSR+QMg==",
+ "mjQS8CpyGnsZIDOIEdYUxg==",
+ "wJpepvmtQQ3sz3tVFDnFqw==",
+ "a4rPqbDWiMivVzaRxvAj7g==",
+ "6o5g9JfKLKQ2vBPqKs6kjg==",
+ "UzPPFSXgeV7KW4CN5GIQXA==",
+ "NdVyHoTbBhX6Umz/9vbi0g==",
+ "Fzuq+Wg7clo6DTujNrxsSA==",
+ "XXFr0WUuGsH5nXPas7hR3Q==",
+ "JVSLiwurnCelNBiG2nflpQ==",
+ "NiawWuMBDo0Q3P2xK/vnLQ==",
+ "nNaGqigseHw30DaAhjBU3g==",
+ "+edqJYGvcy1AH2mEjJtSIg==",
+ "1WIi4I62GqkjDXOYqHWJfQ==",
+ "rwplpbNJz0ADUHTmzAj15Q==",
+ "iWNlSnwrtCmVF89B+DZqOQ==",
+ "tHDbi43e6k6uBgO0hA+Uiw==",
+ "fHNpW230mNib08aB7IM3XQ==",
+ "OChiB4BzcRE8Qxilu6TgJg==",
+ "d+ctfXU0j07rpRRzb5/HDA==",
+ "GDMqfhPQN0PxfJPnK1Bb9A==",
+ "bLd38ZNkVeuhf0joEAxnBQ==",
+ "nvUKoKfC6j8fz3gEDQrc/w==",
+ "fhcbn9xE/6zobqQ2niSBgA==",
+ "HGxe+5/kkh6R9GXzEOOFHA==",
+ "mPwCyD0yrIDonVi+fhXyEQ==",
+ "5PfGtbH9fmVuNnq83xIIgQ==",
+ "XePy/hhnQwHXFeXUQQ55Vg==",
+ "yfAaL0MMtSXPQ37pBdmHxQ==",
+ "NiQ/m4DZXUbpca9aZdzWAw==",
+ "uT6WRh5UpVdeABssoP2VTg==",
+ "oxoZP897lgMg/KLcZAtkAg==",
+ "oKt57TPe4PogmsGssc3Cbg==",
+ "RxmdoO8ak8y/HzMSIm+yBQ==",
+ "6leyDVmC5jglAa98NQ3+Hg==",
+ "+QosBAnSM2h4lsKuBlqEZw==",
+ "hy303iin+Wm7JA6MeelwiQ==",
+ "m9iuy4UtsjmyPzy6FTTZvw==",
+ "f6Ye5F0Lkn34uLVDCzogFQ==",
+ "iGykaF+h4p46HhrWqL8Ffg==",
+ "LPYFDbTEp5nGtG6uO8epSw==",
+ "t2vWMIh2BvfDSQaz5T1TZw==",
+ "OONAvFS/kmH7+vPhAGTNSg==",
+ "g/z9yk94XaeBRFj4hqPzdw==",
+ "2wesXiib76wM9sqRZ7JYwQ==",
+ "n7h9v2N1gOcvMuBEf8uThw==",
+ "ITYL3tDwddEdWSD6J6ULaA==",
+ "inrUwXyKikpOW0y2Kl1wGw==",
+ "iwKBOGDTFzV4aXgDGfyUkw==",
+ "+fcjH2kZKNj8quOytUk4nQ==",
+ "Srl4HivgHMxMOUHyM3jvNw==",
+ "qngzBJbiTB4fivrdnE5gOg==",
+ "G0MlFNCbRjXk4ekcPO/chQ==",
+ "t+bYn9UqrzKiuxAYGF7RLA==",
+ "RVD3Ij6sRwwxTUDAxwELtA==",
+ "RNdyt6ZRGvwYG5Ws3QTuEA==",
+ "9DRHdyX8ECKHUoEsGuqR4Q==",
+ "oMJLQTH1wW7LvOV0KRx/dw==",
+ "bjLZ7ot/X/vWSVx4EYwMCg==",
+ "+p8pofUlwn8vV6Rp6+sz9g==",
+ "cchuqe+CWCJpoakjHLvUfA==",
+ "NvurnIHin4O+wNP7MnrZ1w==",
+ "RBMv0IxXEO3o7MnV47Bzow==",
+ "xTizUioizbMQxD0T6fy/EQ==",
+ "ZCdad3AwhVArttapWFwT/Q==",
+ "Hy1nqC40l5ItxumkIC2LAA==",
+ "W/5ThNLu43uT1O+fg0Fzwg==",
+ "b3BQG9/9qDNC/bNSTBY/sQ==",
+ "neQoa8pvETr07blVMN3pgA==",
+ "oR8rvIZoeoaZ/ufpo0htfQ==",
+ "zEzWZ6l7EKoVUxvk/l78Mw==",
+ "IHyIeMad23fSDisblwyfpA==",
+ "m6srF+pMehggHB1tdoxlPg==",
+ "kggaIvN2tlbZdZRI8S5Apw==",
+ "2RFaMPlSbVuoEqKXgkIa5A==",
+ "//eHwmDOQRSrv+k9C/k3ZQ==",
+ "X/Gha4Ajjm/GStp/tv+Jvw==",
+ "+H0Rglt/HnhZwdty2hsDHg==",
+ "a1aL8zQ+ie3YPogE3hyFFg==",
+ "HxEU37uBMeiR5y8q/pM42g==",
+ "68nqDtXOuxF7DSw6muEZvg==",
+ "s5+78jS4hQYrFtxqTW3g1Q==",
+ "drfODfDI6GyMW7hzkmzQvA==",
+ "pT1raq2fChffFSIBX3fRiA==",
+ "sfowXUMdN2mCoBVrUzulZg==",
+ "AV/YJfdoDUdRcrXVwinhQg==",
+ "3AKEYQqpkfW7CZMFQZoxOw==",
+ "PHwJ5ZAqqftZ4ypr8H1qiQ==",
+ "AoN/pnK4KEUaGw4V9SFjpg==",
+ "soBA65OmZdfBGJkBmY/4Iw==",
+ "mSstwJq7IkJ0JBJ5T8xDKg==",
+ "h13Xuonj+0dD1xH86IhSyQ==",
+ "HK9xG03FjgCy8vSR+hx8+Q==",
+ "oFanDWdePmmZN0xqwpUukA==",
+ "zCRZgVsHbQZcVMHd9pGD3A==",
+ "EvSB+rCggob2RBeXyDQRvQ==",
+ "tXuu7YpZOuMLTv87NjKerA==",
+ "DJ+a37tCaGF5OgUhG+T0NA==",
+ "KkXlgPJPen6HLxbNn5llBw==",
+ "2W6lz1Z7PhkvObEAg2XKJw==",
+ "n+xYzfKmMoB3lWkdZ+D3rg==",
+ "CPDs+We/1wvsGdaiqxzeCQ==",
+ "2Wvk/kouEEOY0evUkQLhOQ==",
+ "ezsm4aFd6+DO9FUxz0A8Pg==",
+ "9sYLg75/hudZaBA3FrzKHw==",
+ "Pp1ZMxJ8yajdbfKM4HAQxA==",
+ "xiyRfVG0EfBA+rCk+tgWRQ==",
+ "/IarsLzJB8bf0AupJJ+/Eg==",
+ "LJeLdqmriyAQp+QjZGFkdQ==",
+ "IhHyHbHGyQS+VawxteLP0w==",
+ "nGzPc0kI/EduVjiK7bzM6Q==",
+ "m06wctjNc3o7iyBHDMZs2w==",
+ "mSJF9dJnxZ15lTC6ilbJ2A==",
+ "xdmY+qyoxxuRZa9kuNpDEg==",
+ "oNOI17POQCAkDwj6lJsYOA==",
+ "p73gSu4d+4T/ZNNkIv9Nlw==",
+ "vOJ55zFdgPPauPyFYBf01w==",
+ "4A+RHIw+aDzw0rSRYfbc7g==",
+ "/gi3UZmunVOIXhZSktZ8zQ==",
+ "a6vem8n6WmRZAalDrHNP0g==",
+ "kGeXrHEN6o7h5qJYcThCPw==",
+ "wrewZ0hoHODf7qmoGcOd7g==",
+ "Z0sjccxzKylgEiPCFBqPSA==",
+ "LKyOFgUKKGUU/PxpFYMILw==",
+ "L2RofFWDO0fVgSz4D2mtdw==",
+ "KI7tQFYW38zYHOzkKp9/lQ==",
+ "ewe/P3pJLYu/kMb5tpvVog==",
+ "IADk81pIu8NIL/+9Fi94pA==",
+ "0L0FVcH5Dlj3oL8+e9Na7g==",
+ "tdiTXKrkqxstDasT0D5BPA==",
+ "R906Kxp2VFVR3VD+o6Vxcw==",
+ "wc+8ohFWgOF4VlSYiZIGwQ==",
+ "wJKFMqh6MGctWfasjHrPEg==",
+ "UHpge5Bldt9oPGo2oxnYvQ==",
+ "vX7RIhatQeXAMr1+OjzhZw==",
+ "s2AKVTwrY65/SWqQxDGJQg==",
+ "Q4bfQslDSqU64MOQbBQEUw==",
+ "mVT74Eht+gAowINoMKV7IQ==",
+ "EuGWtIbyKToOe6DN3NkVpQ==",
+ "ALlGgVDO8So71ccX0D6u2g==",
+ "Rww3qkF3kWSd+AaMT0kfdw==",
+ "hlvtFGW8r0PkbUAYXEM+Hw==",
+ "Oc3BqTF3ZBW3xE0QsnFn/A==",
+ "3j0kFUZ6g+yeeEljx+WXGg==",
+ "8BLkvEkfnOizJq0OTCYGzw==",
+ "Lqel4GdU0ZkfoJVXI5WC/Q==",
+ "rvE64KQGkVkbl07y7JwBqw==",
+ "HbXv8InyZqFT7i3VrllBgg==",
+ "zwQ/3MzTJ9rfBmrANIh14w==",
+ "gglLMohmJDPRGMY1XKndjQ==",
+ "lyfqic/AbEJbCiw+wA01FA==",
+ "XqUO7ULEYhDOuT/I2J8BOA==",
+ "wPhJcp7U7IVX83szbIOOxQ==",
+ "1gA65t5FiBTEgMELTQFUPQ==",
+ "ll2M0QQzBsj5OFi02fv3Yg==",
+ "wt+qDLU38kzNU75ZYi3Hbw==",
+ "a4EYNljinYTx9vb1VvUA6A==",
+ "T6LA+daQqRI38iDKZTdg1A==",
+ "gwyVIrTk5o0YMKQq4lpJ+Q==",
+ "bPRX2zl+K1S0iWAWUn1DZw==",
+ "KQw25X4LnQ9is+qdqfxo0w==",
+ "6tfM6dx3R5TiVKaqYQjnCg==",
+ "OlwHO6Sg2zIwsCOCRu0HiQ==",
+ "mr1qjhliRfl87wPOrJbFQg==",
+ "8c+lvG5sZNimvx9NKNH3ug==",
+ "5Nk2Z94DhlIdfG5HNgvBbQ==",
+ "F50iXjRo1aSTr37GQQXuJA==",
+ "tfgO55QqUyayjDfQh+Zo1Q==",
+ "h7Fc+eT/GuC8iWI+YTD0UQ==",
+ "3TjntNWtpG7VqBt3729L6Q==",
+ "+DWs0vvFGt6d3mzdcsdsyA==",
+ "VJt2kPVBLEBpGpgvuv1oUw==",
+ "XLq/nWX8lQqjxsK9jlCqUg==",
+ "9s3ar9q32Y5A3tla5GW/2Q==",
+ "51yLpfEdvqXmtB6+q27/AQ==",
+ "AiMtfedwGcddA+XYNc+21g==",
+ "p/48hurJ1kh2FFPpyChzJg==",
+ "CRiL6zpjfznhGXhCIbz8pQ==",
+ "/jDVt9dRIn+o4IQ1DPwbsg==",
+ "UNdKik7Vy23LjjPzEdzNsg==",
+ "Koiog/hpN7ew5kgJbty34A==",
+ "4itEKfbRCJvqlgKnyEdIOQ==",
+ "zi04Yc01ZheuFAQc59E45A==",
+ "etRjRvfL/IwceY/IJ1tgzQ==",
+ "3sNJJIx1NnjYcgJhjOLJOg==",
+ "4yVqq66iHYQjiTSxGgX2oA==",
+ "Q8RVI/kRbKuXa8HAQD7zUA==",
+ "OERGn45uzfDfglzFFn6JAg==",
+ "JGEy6VP3sz3LHiyT2UwNHQ==",
+ "1zDfWw5LdG20ClNP1HYxgw==",
+ "TGB+FIzzKnouLh5bAiVOQg==",
+ "n5GA+pA9mO/f4RN9NL9lNg==",
+ "bUxQBaqKyvlSHcuRL9whjg==",
+ "tOdlnsE3L3XCBDJRmb/OqA==",
+ "XdkxmYYooeDKzy7PXVigBQ==",
+ "PMvG4NqJP76kMRAup6TSZA==",
+ "qpFJZqzkklby+u1UT3c1iA==",
+ "fW3QZyq5UixIA1mP6eWgqQ==",
+ "9nMltdrrBmM5ESBY2FRjGA==",
+ "1Vtrv6QUAfiYQjlLTpNovg==",
+ "ur9JDCVNwzSH4q4ngDlHNQ==",
+ "4u3eyKc+y3uRnkASrgBVUw==",
+ "XddlSluOH6VkR7spFIFmdQ==",
+ "NOmu8oZc6CcKLu+Wfz2YOQ==",
+ "3Ejtsqw3Iep/UQd0tXnSlg==",
+ "y/e3HSdg7T19FanRpJ7+7Q==",
+ "YodhkayN5wsgPZEYN7/KNA==",
+ "pZfn6IiG+V28fN8E2hawDQ==",
+ "jGHMJqbj6X1NdTDyWmXYAQ==",
+ "olTSlmirL9MFhKORiOKYkQ==",
+ "CrJDgdfzOea2M2hVedTrIg==",
+ "fpXijBOM3Ai1RkmHven5Ww==",
+ "eLYKLr4labZeLiRrDJ9mnA==",
+ "9vmJUS7WIVOlhMqwipAknQ==",
+ "G7J/za99BFbAZH+Q+/B8WA==",
+ "Hb+pdSavvJ9lUXkSVZW8Og==",
+ "gTB2zM3RPm27mUQRXc/YRg==",
+ "e5KCqQ/1GAyVMRNgQpYf6g==",
+ "1ApqwW7pE+XUB2Cs2M6y7g==",
+ "/wiA2ltAuWyBhIvQAYBTQw==",
+ "HFCQEiZf7/SNc+oNSkkwlA==",
+ "JFi6N1PlrpKaYECOnI7GFg==",
+ "E4ojRDwGsIiyuxBuXHsKBA==",
+ "+25t/2lo0FUEtWYK8LdQZQ==",
+ "up2MVDi9ve+s83/nwNtZ7Q==",
+ "cXpfd6Io6Glj2/QzrDMCvA==",
+ "DCvI9byhw0wOFwF1uP6xIQ==",
+ "PibGJQNw7VHPTgqeCzGUGA==",
+ "0ZRGz+oj2infCAkuKKuHiQ==",
+ "2QS/6OBA1T01NlIbfkTYJg==",
+ "P14k+fyz0TG9yIPdojp52w==",
+ "g5EzTJ0KA4sO3+Opss3LMg==",
+ "R5oOM58zdbVxFSDQnNWqeA==",
+ "Vg2E5qEDfC+QxZTZDCu9yQ==",
+ "YPgMthbpcBN2CMkugV60hQ==",
+ "gZWTFt5CuLqMz6OhWL+hqQ==",
+ "YrEP9z2WPQ8l7TY1qWncDA==",
+ "7p4NpnoNSQR7ISg+w+4yFg==",
+ "9L6yLO93sRN70+3qq3ObfA==",
+ "QH36wzyIhh6I56Vnx79hRA==",
+ "9DtM1vls4rFTdrSnQ7uWXw==",
+ "ZlOAnCLV1PkR0kb3E+Nfuw==",
+ "9UhKmKtr4vMzXTEn74BEhg==",
+ "Ndx5LDiVyyTz/Fh3oBTgvA==",
+ "mXZ4JeBwT2WJQL4a/Tm4jQ==",
+ "N9nD7BGEM7LDwWIMDB+rEQ==",
+ "dmAfbd9F0OJHRAhNMEkRsA==",
+ "jV/D2B11NLXZRH77sG9lBw==",
+ "1C50kisi9nvyVJNfq2hOEQ==",
+ "NMbAjbnuK7EkVeY3CQI5VA==",
+ "J1nYqJ7tIQK1+a/3sMXI/Q==",
+ "m416yrrAlv+YPClGvGh+qQ==",
+ "rLZII1R6EGus+tYCiUtm6g==",
+ "xktOghh1S9nIX6fXWnT+Ug==",
+ "FcFcn4qmPse5mJCX5yNlsA==",
+ "xAAipGfHTGTjp9Qk1MR8RQ==",
+ "RQOlmzHwQKFpafKPJj0D8w==",
+ "WRjYdKdtnd1G9e/vFXCt0g==",
+ "z0BU//aSjYHAkGGk3ZSGNg==",
+ "M55eersiJuN9v61r8DoAjQ==",
+ "l2mAbuFF3QBIUILDODiUHQ==",
+ "IhpXs1TK7itQ3uTzZPRP5Q==",
+ "t2EkpUsLOEOsrnep0nZSmA==",
+ "lMaO8Yf+6YNowGyhDkPhQA==",
+ "UbSFw5jtyLk5MealqJw++A==",
+ "5u2PdDcIY3RQgtchSGDCGg==",
+ "MQYM3BT77i35LG9HcqxY2Q==",
+ "8AfCSZC0uasVON9Y/0P2Pw==",
+ "evaWFoxZNQcRszIRnxqB+A==",
+ "+8PiQt6O7pJI/nIvQpDaAg==",
+ "eRwaYiog2DdlGQyaltCMJg==",
+ "JyUJEnU6hJu8x2NCnGrYFw==",
+ "l0E0U/CJsyCVSTsXW4Fp+w==",
+ "XV13yK0QypJXmgI+dj4KYw==",
+ "jrRH0aTUYCOpPLZwzwPRfQ==",
+ "N3YDSkBUqSmrmNvZZx4a1Q==",
+ "0yJ7TQYzcp3DXVSvwavr+w==",
+ "rhgtLQh0F9bRA6IllM7AGw==",
+ "IWZnTJ3Hb9qw9HAK/M9gTw==",
+ "izeyFvXOumNgVyLrbKW45g==",
+ "xYD8jrCDmuQna+p1ebnKDQ==",
+ "SOdpdrk2ayeyv0xWdNuy9g==",
+ "HYylUirJRqLm+dkp39fSOQ==",
+ "q4z6A4l3nhX3smTmXr+Sig==",
+ "Zyo0fzewcqXiKe2mAwKx5g==",
+ "LMEtzh0+J27+4zORfcjITw==",
+ "LoUv/f2lcWpjftzpdivMww==",
+ "mXBfDUt/sBW5OUZs2sihvw==",
+ "PggVPQL5YKqSU/1asihcrg==",
+ "mI0eT4Rlr7QerMIngcu/ng==",
+ "NmQrsmb8PVP05qnSulPe5Q==",
+ "TcyyXrSsQsnz0gJ36w4Dxw==",
+ "y4mfEDerrhaqApDdhP5vjA==",
+ "ynaj4XjU27b7XbqPyxI8Ig==",
+ "Ua6aO6HwM+rY4sPR19CNFA==",
+ "3go7bJ9WqH/PPUTjNP3q/Q==",
+ "n1ixvP7SfwYT3L2iWpJg6A==",
+ "W8y32OLHihfeV0XFw7LmOg==",
+ "uzkNhmo2d08tv5AmnyqkoQ==",
+ "hJ8leLNuJ6DK5V8scnDaZQ==",
+ "KodYHHN62zESrXUye7M01g==",
+ "H+yPRiooEh5J7lAJB4RZ7Q==",
+ "dZg5w8rFETMp9SgW7m0gfg==",
+ "LsmsPokAwWNCuC74MaqFCQ==",
+ "1QGhj9NONF2rC44UdO+Izw==",
+ "uwGivY3/C9WK+dirRPJZ4A==",
+ "rXGWY/Gq+ZEsmvBHUfFMmQ==",
+ "j4FBMnNfdBwx0VsDeTvhFg==",
+ "81nkjWtpBhqhvOp6K8dcWg==",
+ "dCDaYYrgASXPMGFRV0RCGg==",
+ "Kj1QI+s9261S3lTtPKd9eg==",
+ "LblwOqNiciHmt2NXjd89tg==",
+ "46piyANQVvvLqcoMq5G8tQ==",
+ "XJihma9zSRrXLC+T+VcFDA==",
+ "K3NBEG8jJTJbSrYSOC3FKw==",
+ "cT3PwwS6ALZA/na9NjtdzA==",
+ "wJ4uCrl4DPg70ltw1dZO3w==",
+ "JATLdpQm//SQnkyCfI5x7Q==",
+ "X1PaCfEDScclLtOTiF5JUw==",
+ "444F9T6Y7J67Y9sULG81qg==",
+ "8JVHFRwAd/SCLU0CRJYofg==",
+ "aLh1XEUrfR9W82gzusKcOg==",
+ "U+bB5NjFIuQr/Y5UpXHwxA==",
+ "Egs14xVbRWjfBBX7X5Z60g==",
+ "KSorNz/PLR/YYkxaj1fuqw==",
+ "RDgGGxTtcPvRg/5KRRlz4w==",
+ "5T39s5CtSrK5awMPUcEWJg==",
+ "+PUVXkoTqHxJHO18z4KMfw==",
+ "Bvk8NX4l6WktLcRDRKsK/A==",
+ "kNGIV3+jQmJlZDTXy1pnyA==",
+ "E3jMjAgXwvwR8PA53g4+PQ==",
+ "MbI04HlTGCoc/6WDejwtaQ==",
+ "aEnHUfn7UE/Euh6jsMuZ7g==",
+ "z4Bft++f72QeDh4PWGr/sw==",
+ "1lCcQWGDePPYco4vYrA5vw==",
+ "iu5csar0IQQBOTgw5OvJwQ==",
+ "raKMXnnX6PFFsbloDqyVzQ==",
+ "uPnL9tboMZo0Kl2fe24CmA==",
+ "8OFxXwnPmrogpNoueZlC4Q==",
+ "V6CRKrKezPwsRdbm0DJ2Yg==",
+ "xmGgK3W5y+oCd0K2u8XjZQ==",
+ "Ry3zgZ6KHrpNyb7+Tt2Pkw==",
+ "IwLbkL33z+LdTjaFYh93kg==",
+ "caepyBOAFu0MxbcXrGf6TA==",
+ "iIWxFdolLcnXqIjPMg+5kQ==",
+ "P430CeF2MDkuq11YdjvV8A==",
+ "yCu+DVU/ceMTOZ5h/7wQTg==",
+ "4mQVNv7FHj+/O6XFqWFt/Q==",
+ "OEJ40VmMDYzc2ESEMontRA==",
+ "D66Suu3tWBD+eurBpPXfjA==",
+ "RNK9G1hfuz3ETY/RmA9+aA==",
+ "BYpHADmEnzBsegdYTv8B5Q==",
+ "DBKrdpCE0awppxST4o/zzg==",
+ "KOmdvm+wJuZ/nT/o1+xOuw==",
+ "gDxqUdxxeXDYhJk9zcrNyA==",
+ "UPzS4LR3p/h0u69+7YemrQ==",
+ "hf9HFxWRNX2ucH8FLS7ytA==",
+ "ozVqYsmUueKifb4lDyVyrg==",
+ "TfHvdbl2M4deg65QKBTPng==",
+ "SzCGM8ypE58FLaR1+1ccxQ==",
+ "3nthUmLZ30HxQrzr2d7xFA==",
+ "1jBaRO8Bg5l6TH7qJ8EPiw==",
+ "eJlcN+gJnqAnctbWSIO9uA==",
+ "G8LFBop8u6IIng+gQuVg3w==",
+ "3JhnM6G4L06NHt31lR0zXA==",
+ "342VOUOxoLHUqtHANt83Hw==",
+ "hRxbdeniAVFgKUgB9Q3Y+g==",
+ "cFFE2R4GztNoftYkqalqUQ==",
+ "YmaksRzoU+OwlpiEaBDYaQ==",
+ "jon1y9yMEGfiIBjsDeeJdA==",
+ "oSnrpW4UmmVXtUGWqLq+tQ==",
+ "zaqyy3GaJ7cp8qDoLJWcTw==",
+ "luO1R8dUM9gy1E2lojRQoA==",
+ "YHM6NNHjmodv+G0mRLK7kw==",
+ "ZSmN8mmI9lDEHkJqBBg0Nw==",
+ "520wTzrysiRi2Td92Zq0HQ==",
+ "RAAw14BA1ws5Wu/rU7oegw==",
+ "vb6Agwzk4JG0Nn7qRPPFMQ==",
+ "joDXdLpXvRjOqkRiYaD/Sw==",
+ "dK2DU3t1ns+DWDwfBvH3SQ==",
+ "gZNJ1Qq6OcnwXqc+jXzMLQ==",
+ "R8ULpSNu9FcCwXZM0QedSg==",
+ "mc45FSMtzdw2PTcEBwHWPw==",
+ "d0qvm3bl38rRCpYdWqolCQ==",
+ "o9tdzmIu+3J/EYU4YWyTkA==",
+ "5eXpiczlRdmqMYSaodOUiQ==",
+ "KYuUNrkTvjUWQovw9dNakA==",
+ "02im2RooJQ/9UfUrh5LO+A==",
+ "kWPUUi7x9kKKa6nJ+FDR5Q==",
+ "6z8CRivao3IMyV4p4gMh7g==",
+ "SmRWEzqddY9ucGAP5jXjAg==",
+ "DJscTYNFPyPmTb57g/1w+Q==",
+ "uOHrw37yF9oLLVd16nUpeg==",
+ "HaIRV9SNPRTPDOSX9sK/bg==",
+ "K4yZNVoqHjXNhrZzz2gTew==",
+ "bTNRjJm+FfSQVfd56nNNqQ==",
+ "x5lyMArsv1MuJmEFlWCnNw==",
+ "cxpZ4bloGv734LBf4NpVhA==",
+ "kUudvRfA33uJDzHIShQd3Q==",
+ "3Wfj05vCLFAB9vII5AU9tw==",
+ "FUQySDFodnRhr+NUsWt0KA==",
+ "eC/RcoCVQBlXdE9WtcgXIw==",
+ "NoX8lkY+kd2GPuGjp+s0tQ==",
+ "EzjbinBHx3Wr08eXpH3HXA==",
+ "0VsaJHR0Ms8zegsCpAKoyg==",
+ "e2xLFVavnZIUUtxJx+qa1g==",
+ "Kt6BTG1zdeBZ3nlVk+BZKQ==",
+ "EUXQZwLgnDG+C8qxVoBNdw==",
+ "0SkC/4PtnX1bMYgD6r6CLA==",
+ "rzj6mjHCcMEouL66083BAg==",
+ "V5HEaY3v9agOhsbYOAZgJA==",
+ "tJt6VDdAPEemBUvnoc4viA==",
+ "g0lWrzEYMntVIahC7i0O2g==",
+ "zCpibjrZOA3FQ4lYt0WoVA==",
+ "4Xh/B3C16rrjbES+FM1W8g==",
+ "GHEdXgGWOeOa6RuPMF0xXg==",
+ "3kREs/qaMX0AwFXN0LO5ow==",
+ "GLDNTSwygNBmuFwCIm7HtA==",
+ "JBkbaBiorCtFq9M9lSUdMg==",
+ "rJCuanCy51ydVD4nInf9IQ==",
+ "OzFRv+PzPqTNmOnvZGoo5g==",
+ "7mxU5fJl/c6dXss9H3vGcQ==",
+ "9J53kk+InE3CKa7cPyCXMw==",
+ "x9TIZ9Ua++3BX+MpjgTuWA==",
+ "h0MH5NGFfChgmRJ3E/R3HQ==",
+ "25w3ZRUzCvJwAVHYCIO5uw==",
+ "1Wc8jQlDSB4Dp32wkL2odw==",
+ "ipPPjxpXHS1tcykXmrHPMQ==",
+ "r95wJtP5rsTExKMS7QhHcw==",
+ "TZT86wXfzFffjt0f95UF5w==",
+ "VpmBstwR7qPVqPgKYQTA3g==",
+ "3++dZXzZ6AFEz7hK+i5hww==",
+ "mAiD16zf+rCc7Qzxjd5buA==",
+ "1JI9bT92UzxI8txjhst9LQ==",
+ "TNyvLixb03aP2f8cDozzfA==",
+ "spHVvA/pc7nF9Q4ON020+w==",
+ "GA8k6GQ20DGduVoC+gieRA==",
+ "T7waQc3PvTFr0yWGKmFQdQ==",
+ "P0Pc8owrqt6spdf7FgBFSw==",
+ "DKApp/alXiaPSRNm3MfSuA==",
+ "UreSZCIdDgloih8KLeX7gg==",
+ "xJi0T+psHOXMivSOVpMWeQ==",
+ "cNsC9bH30eM1EZS6IdEdtQ==",
+ "XjjrIpsmATV/lyln4tPb+g==",
+ "qt5CsMts2aD4lw/4Q6bHYQ==",
+ "h+KRDKIvyVUBmRjv1LcCyg==",
+ "2j83jrPwPfYlpJJ2clEBYQ==",
+ "ZrCezGLz38xKmzAom6yCTQ==",
+ "SEGu+cSbeeeZg4xWwsSErQ==",
+ "Duz/8Ebbd0w6oHwOs0Wnwg==",
+ "Ci7sS7Yi1+IwAM3VMAB4ew==",
+ "DG2Qe2DqPs5MkZPOqX363Q==",
+ "v0Bvws1WYVoEgDt8xmVKew==",
+ "CtDj/h2Q/lRey20G8dzSgA==",
+ "WRoJMO0BCJyn5V6qnpUi4Q==",
+ "RQywrOLZEKw9+kG6qTzr3g==",
+ "mU4CqbAwpwqegxJaOz9ofQ==",
+ "aN5x46Gw1VihRalwCt1CGg==",
+ "U6VQghxOXsydh3Naa5Nz4A==",
+ "YA+zdEC+yEgFWRIgS1Eiqw==",
+ "oPcxgoismve6+jXyIKK6AQ==",
+ "PqLCd/pwc+q5GkL6MB0jTg==",
+ "fHL+fHtDxhALZFb9W/uHuw==",
+ "dhTevyxTYAuKbdLWhG47Kw==",
+ "VllbOAjeW3Dpbj5lp2OSmA==",
+ "3itfXtlLPRmPCSYaSvc39Q==",
+ "GNak/LFeoHWlTdLW1iU4eg==",
+ "HuDuxs2KiGqmeyY1s1PjpQ==",
+ "xs8J3cesq7lDhP/dNltqOw==",
+ "foXSDEUwMhfHWJSmSejsQg==",
+ "6fWom3YoKvW6NIg6y9o9CQ==",
+ "NhZbSq0CjDNOAIvBHBM9zA==",
+ "5w4FbRhWACP7k2WnNitiHg==",
+ "0UeRwDID2RBIikInqFI7uw==",
+ "/y/jHHEpUu5TR+R2o96kXA==",
+ "voO3krg4sdy4Iu+MZEr8+g==",
+ "hdzol5dk//Q6tCm4+OndIA==",
+ "Nc5kiwXCAyjpzt43G5RF1A==",
+ "3UBYBMejKInSbCHRoJJ7dg==",
+ "dRFCIbVu0Y8XbjG5i+UFCQ==",
+ "t8pjhdyNJirkvYgWIO/eKg==",
+ "FAXzjjIr8l1nsQFPpgxM/g==",
+ "SPGpjEJrpflv1hF0qsFlPw==",
+ "9Y1ZmfiHJd9vCiZ6KfO1xQ==",
+ "7Eqzyb+Kep+dIahYJWNNxQ==",
+ "9rL8nC/VbSqrvnUtH9WsxQ==",
+ "H4FZ5Wcnb40hQM1DMGGe8A==",
+ "AjoXWGb/l9xH/hscgEc6kQ==",
+ "6nzFl41uutgDdC30oOeCqg==",
+ "3jo1jRy3MybXtoLR+JIbJw==",
+ "mXdE08dv+OlIhlcqMBH2Gg==",
+ "Ifd7DI6o8N5gnyAKqZTlRw==",
+ "JNUvg/kxL3rdcZnD4IqUxw==",
+ "ry8B+sAHNeFIZHCCDynFyw==",
+ "TXaEd5lIKhzjcncfNcBgSg==",
+ "Mr3ehuDMUimOSn+FlkchdA==",
+ "cwiGhjmX9v8I7E/ekQ0h+g==",
+ "I/r5+1jnqumCPprKC/2BqA==",
+ "S4V3MfGYk8I4fd3WH09yYw==",
+ "A+crVyUeynAkEMYKbnFjZw==",
+ "vtyHcNQPcUTRuZcQvRUX4Q==",
+ "UNKx1ZVv3HNp21zrUSm6ew==",
+ "rsAlvGLv2D0swd6ol3WlvA==",
+ "2qwqb8ENAR2fpQnw55sPDw==",
+ "xBJJuYYnsTJOeFggZSKC4Q==",
+ "omvtZZKruPiEt6fV0YXTdg==",
+ "JZEgKUhUN+USJsvtF4HZOg==",
+ "euG/kpJ5elSDOGNbWWDfNQ==",
+ "DiiVmM6/WNcp0MUjSaFq6w==",
+ "QCNS8gAml1M2pJ+MxZsueg==",
+ "M6+pggFsHfM3alFxcMOFNQ==",
+ "YLoWpDTwXnszEQm8FA164Q==",
+ "N08oUZtlXbQvO9t3vXnGog==",
+ "jkjuJowWuOa4CLY+RZiErQ==",
+ "mPf+S+6oAoVIYEVveaiNFA==",
+ "R0iVyo5qreP/68uZlZphDA==",
+ "GYlqhQgp03B0mXpUhQ+ZCA==",
+ "lQNbmWD7PhwNGye+zbc3GQ==",
+ "cNeaOJEOzUSDdRmenPQyuw==",
+ "Gp66/Txv6ebv5bn85TuQtA==",
+ "xAda6DVkcvvqhI8vWZeGyA==",
+ "Ggk1Qa0lEdAgCXG6SmCkBA==",
+ "MYuO7ZURXtyaf56q7hH4Zw==",
+ "RUIdZRTgJBudWUZQFgiFaQ==",
+ "bgFJxLirUom2zT0h7LdOpw==",
+ "A2gaOpIlrS7TKVQgy9XMSw==",
+ "zevXp0lqqnXv9X6Bgmjtqg==",
+ "a5iuFqWAdFFsRgp7SFYwNg==",
+ "TxTy0TaDsWTcRH3wdBEQLQ==",
+ "jephVdKDeJIhXPrdMOJ4qA==",
+ "C4KdamfqUPuJ3RGFdpIEdw==",
+ "zl6l2Ioz1qovRUIWrSyxVA==",
+ "+gGaDxUe0UnNrf3PPg1qQQ==",
+ "1HgbrlaLMHS6Qj/0kkaJxg==",
+ "eGxTly6Pnu7eV/MKYMmuYw==",
+ "RAMKfnlrzNjpyh2BWt6JHg==",
+ "4pZQm9ogCZ/EAR9pjJm1eA==",
+ "l1zv3erwXIegQFd02NlCag==",
+ "uHGyRZchuA4ulmuD5LqquQ==",
+ "/vFu89tsV+lbcoiqM/XWog==",
+ "63SUgqfQimrmjvy/bEDQ0w==",
+ "JLHuf+FlChFDa9LYfTQ4Eg==",
+ "I+ZnPePTFX8ZODe14bxgyA==",
+ "CtoK1k3U82BkvzuPfQ4pjQ==",
+ "6nqQm4C7y+wZ+qX0kVjwmA==",
+ "+C3kBxRXIjqBk0EJxe3Xfg==",
+ "qVu748pIxEZtiywg4/4qhw==",
+ "07o+sKjjRCYkwy/ACyoYhg==",
+ "CiLF4dkbLURekBcQbwPUVA==",
+ "W/N5/nkp4iQIPYfAagVV7A==",
+ "3PJOphhEjw0E4arTfVVwdg==",
+ "YdMbARHwB+bSOd0PlTlXiA==",
+ "41hbx5Yr7UWxsV6+bWUYUA==",
+ "SqJHXD0MorNwHtHL9TbWLg==",
+ "pWKGUzm/muwOiBtzkRMnRg==",
+ "az9zZ7HTa4FJGRQMcamvEw==",
+ "zavAAN8C9Wo8oBLyztp63Q==",
+ "yBAnPmwrMJ8kpPP292S/Lw==",
+ "E6szQhjuUAz2e0h9ffQfEQ==",
+ "Fs3cQxQyS9kM4T8j5R7rWw==",
+ "GB5fRLZxnjRUfEe0SwcePQ==",
+ "+9OY8xkT9dM/rb2T6ACtOQ==",
+ "If2xFBD1p91iDD7ZrsfgjA==",
+ "QCFfoMhy8EleZAOpfRY88w==",
+ "NobWPk1Z6bHt5s9NHXt/pg==",
+ "nK6T4vV4384OIcqO5tQMhA==",
+ "Zov1EzK+VomiuwT1+ulQ8g==",
+ "pF98OKDvLUlnTzo7wmlpOw==",
+ "Wrq9YDsieAMC3Y2DSY5Rcg=="
+ ]
+}
diff --git a/application/basilisk/base/content/newtab/newTab.js b/application/basilisk/base/content/newtab/newTab.js
index 1731edadc..bbd2ef39d 100644
--- a/application/basilisk/base/content/newtab/newTab.js
+++ b/application/basilisk/base/content/newtab/newTab.js
@@ -11,6 +11,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PageThumbs.jsm");
Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm");
+Cu.import("resource:///modules/DirectoryLinksProvider.jsm");
Cu.import("resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Rect",
diff --git a/application/basilisk/base/content/newtab/newTab.xhtml b/application/basilisk/base/content/newtab/newTab.xhtml
index 7de1ff3d4..eef51b4b2 100644
--- a/application/basilisk/base/content/newtab/newTab.xhtml
+++ b/application/basilisk/base/content/newtab/newTab.xhtml
@@ -73,6 +73,7 @@
<div id="newtab-horizontal-margin">
<div class="newtab-side-margin"/>
<div id="newtab-grid">
+ <h1 id="topsites-heading"/>
</div>
<div class="newtab-side-margin"/>
</div>
diff --git a/application/basilisk/base/content/newtab/page.js b/application/basilisk/base/content/newtab/page.js
index b92d3d5ce..f7626ced2 100644
--- a/application/basilisk/base/content/newtab/page.js
+++ b/application/basilisk/base/content/newtab/page.js
@@ -48,6 +48,11 @@ var gPage = {
let enabled = gAllPages.enabled;
this._updateAttributes(enabled);
+ // Update thumbnails to the new enhanced setting
+ if (aData == "browser.newtabpage.enhanced") {
+ this.update();
+ }
+
// Initialize the whole page if we haven't done that, yet.
if (enabled) {
this._init();
@@ -74,7 +79,10 @@ var gPage = {
update(reason = "") {
// Update immediately if we're visible.
if (!document.hidden) {
- if (gGrid.ready) {
+ // Ignore updates where reason=links-changed as those signal that the
+ // provider's set of links changed. We don't want to update visible pages
+ // in that case, it is ok to wait until the user opens the next tab.
+ if (reason != "links-changed" && gGrid.ready) {
gGrid.refresh();
}
@@ -111,6 +119,10 @@ var gPage = {
document.getElementById("newtab-search-submit").value =
document.body.getAttribute("dir") == "ltr" ? "\u25B6" : "\u25C0";
+ if (Services.prefs.getBoolPref("browser.newtabpage.compact")) {
+ document.body.classList.add("compact");
+ }
+
// Initialize search.
gSearch.init();
@@ -248,6 +260,8 @@ var gPage = {
onPageVisibleAndLoaded() {
// Send the index of the last visible tile.
this.reportLastVisibleTileIndex();
+ // Maybe tell the user they can undo an initial automigration
+ this.maybeShowAutoMigrationUndoNotification();
},
reportLastVisibleTileIndex() {
@@ -273,5 +287,11 @@ var gPage = {
}
}
}
- }
+
+ DirectoryLinksProvider.reportSitesAction(sites, "view", lastIndex);
+ },
+
+ maybeShowAutoMigrationUndoNotification() {
+ sendAsyncMessage("NewTab:MaybeShowAutoMigrationUndoNotification");
+ },
};
diff --git a/application/basilisk/base/content/newtab/sites.js b/application/basilisk/base/content/newtab/sites.js
index b952deca5..9d103ce9b 100644
--- a/application/basilisk/base/content/newtab/sites.js
+++ b/application/basilisk/base/content/newtab/sites.js
@@ -171,8 +171,11 @@ Site.prototype = {
// first check for end time, as it may modify the link
this._checkLinkEndTime();
// setup display variables
+ let enhanced = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link);
let url = this.url;
- let title = this.link.type == "history" ? this.link.baseDomain : this.title;
+ let title = enhanced && enhanced.title ? enhanced.title :
+ this.link.type == "history" ? this.link.baseDomain :
+ this.title;
let tooltip = (this.title == url ? this.title : this.title + "\n" + url);
let link = this._querySelector(".newtab-link");
@@ -241,7 +244,8 @@ Site.prototype = {
*/
refreshThumbnail: function Site_refreshThumbnail() {
// Only enhance tiles if that feature is turned on
- let link = this.link;
+ let link = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link) ||
+ this.link;
let thumbnail = this._querySelector(".newtab-thumbnail.thumbnail");
if (link.bgColor) {
@@ -263,6 +267,16 @@ Site.prototype = {
placeholder.style.backgroundColor = "hsl(" + hue + ",80%,40%)";
placeholder.textContent = link.baseDomain.substr(0,1).toUpperCase();
}
+
+ if (link.enhancedImageURI) {
+ let enhanced = this._querySelector(".enhanced-content");
+ enhanced.style.backgroundImage = 'url("' + link.enhancedImageURI + '")';
+
+ if (this.link.type != link.type) {
+ this.node.setAttribute("type", "enhanced");
+ this.enhancedId = link.directoryId;
+ }
+ }
},
_ignoreHoverEvents: function(element) {
@@ -282,6 +296,13 @@ Site.prototype = {
this._node.addEventListener("dragstart", this, false);
this._node.addEventListener("dragend", this, false);
this._node.addEventListener("mouseover", this, false);
+
+ // Specially treat the sponsored icon & suggested explanation
+ // text to prevent regular hover effects
+ let sponsored = this._querySelector(".newtab-sponsored");
+ let suggested = this._querySelector(".newtab-suggested");
+ this._ignoreHoverEvents(sponsored);
+ this._ignoreHoverEvents(suggested);
},
/**
@@ -312,6 +333,31 @@ Site.prototype = {
.add(aIndex);
},
+ _toggleLegalText: function(buttonClass, explanationTextClass) {
+ let button = this._querySelector(buttonClass);
+ if (button.hasAttribute("active")) {
+ let explain = this._querySelector(explanationTextClass);
+ explain.parentNode.removeChild(explain);
+
+ button.removeAttribute("active");
+ }
+ else {
+ let explain = document.createElementNS(HTML_NAMESPACE, "div");
+ explain.className = explanationTextClass.slice(1); // Slice off the first character, '.'
+ this.node.appendChild(explain);
+
+ let link = '<a href="' + TILES_EXPLAIN_LINK + '">' +
+ newTabString("learn.link") + "</a>";
+ let type = (this.node.getAttribute("suggested") && this.node.getAttribute("type") == "affiliate") ?
+ "suggested" : this.node.getAttribute("type");
+ let icon = '<input type="button" class="newtab-control newtab-' +
+ (type == "enhanced" ? "customize" : "control-block") + '"/>';
+ explain.innerHTML = newTabString(type + (type == "sponsored" ? ".explain2" : ".explain"), [icon, link]);
+
+ button.setAttribute("active", "true");
+ }
+ },
+
/**
* Handles site click events.
*/
@@ -330,13 +376,31 @@ Site.prototype = {
action = "click";
}
}
+ // Handle sponsored explanation link click
+ else if (target.parentElement.classList.contains("sponsored-explain")) {
+ action = "sponsored_link";
+ }
+ else if (target.parentElement.classList.contains("suggested-explain")) {
+ action = "suggested_link";
+ }
// Only handle primary clicks for the remaining targets
else if (button == 0) {
aEvent.preventDefault();
if (target.classList.contains("newtab-control-block")) {
+ // Notify DirectoryLinksProvider of suggested tile block, this may
+ // affect if and how suggested tiles are recommended and needs to
+ // be reported before pages are updated inside block() call
+ if (this.link.targetedSite) {
+ DirectoryLinksProvider.handleSuggestedTileBlock();
+ }
this.block();
action = "block";
}
+ else if (target.classList.contains("sponsored-explain") ||
+ target.classList.contains("newtab-sponsored")) {
+ this._toggleLegalText(".newtab-sponsored", ".sponsored-explain");
+ action = "sponsored";
+ }
else if (pinned && target.classList.contains("newtab-control-pin")) {
this.unpin();
action = "unpin";
@@ -349,6 +413,11 @@ Site.prototype = {
action = "pin";
}
}
+
+ // Report all link click actions
+ if (action) {
+ DirectoryLinksProvider.reportSitesAction(gGrid.sites, action, tileIndex);
+ }
},
/**
diff --git a/application/basilisk/base/jar.mn b/application/basilisk/base/jar.mn
index 845237e3e..5ec92d79a 100644
--- a/application/basilisk/base/jar.mn
+++ b/application/basilisk/base/jar.mn
@@ -125,6 +125,8 @@ browser.jar:
content/browser/newtab/newTab.xhtml (content/newtab/newTab.xhtml)
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
content/browser/newtab/newTab.css (content/newtab/newTab.css)
+ content/browser/newtab/newTab.inadjacent.json (content/newtab/newTab.inadjacent.json)
+ content/browser/newtab/alternativeDefaultSites.json (content/newtab/alternativeDefaultSites.json)
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js)
content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css)
diff --git a/application/basilisk/components/nsBrowserGlue.js b/application/basilisk/components/nsBrowserGlue.js
index 6138e151d..3258159b6 100644
--- a/application/basilisk/components/nsBrowserGlue.js
+++ b/application/basilisk/components/nsBrowserGlue.js
@@ -32,6 +32,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s
["ContentPrefServiceParent", "resource://gre/modules/ContentPrefServiceParent.jsm"],
["ContentSearch", "resource:///modules/ContentSearch.jsm"],
["DateTimePickerHelper", "resource://gre/modules/DateTimePickerHelper.jsm"],
+ ["DirectoryLinksProvider", "resource:///modules/DirectoryLinksProvider.jsm"],
["Feeds", "resource:///modules/Feeds.jsm"],
["FileUtils", "resource://gre/modules/FileUtils.jsm"],
["FormValidationHandler", "resource:///modules/FormValidationHandler.jsm"],
@@ -656,7 +657,9 @@ BrowserGlue.prototype = {
webrtcUI.init();
AboutHome.init();
+ DirectoryLinksProvider.init();
NewTabUtils.init();
+ NewTabUtils.links.addProvider(DirectoryLinksProvider);
AboutNewTab.init();
NewTabMessages.init();
diff --git a/application/basilisk/configure.in b/application/basilisk/configure.in
index 9638c1e4d..8527d218c 100644
--- a/application/basilisk/configure.in
+++ b/application/basilisk/configure.in
@@ -8,6 +8,9 @@ dnl Things we need to carry from confvars.sh
AC_DEFINE(MOZ_PHOENIX)
AC_SUBST(MOZ_PHOENIX)
+AC_DEFINE(MOZ_AUSTRALIS)
+AC_SUBST(MOZ_AUSTRALIS)
+
AC_DEFINE(MC_BASILISK)
AC_SUBST(MC_BASILISK)
diff --git a/application/basilisk/confvars.sh b/application/basilisk/confvars.sh
index 0343034a4..48985f16a 100644
--- a/application/basilisk/confvars.sh
+++ b/application/basilisk/confvars.sh
@@ -6,6 +6,7 @@
MOZ_APP_BASENAME=Basilisk
MOZ_APP_VENDOR=Moonchild
MOZ_PHOENIX=1
+MOZ_AUSTRALIS=1
MC_BASILISK=1
MOZ_UPDATER=1
diff --git a/application/basilisk/installer/package-manifest.in b/application/basilisk/installer/package-manifest.in
index 27dfc4e05..6f80a7882 100644
--- a/application/basilisk/installer/package-manifest.in
+++ b/application/basilisk/installer/package-manifest.in
@@ -297,7 +297,6 @@
@RESPATH@/components/toolkit_finalizationwitness.xpt
@RESPATH@/components/toolkit_formautofill.xpt
@RESPATH@/components/toolkit_osfile.xpt
-@RESPATH@/components/toolkit_securityreporter.xpt
@RESPATH@/components/toolkit_perfmonitoring.xpt
@RESPATH@/components/toolkit_xulstore.xpt
@RESPATH@/components/toolkitprofile.xpt
@@ -584,10 +583,6 @@
@RESPATH@/components/PrivateBrowsing.manifest
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
-; Security Reports
-@RESPATH@/components/SecurityReporter.manifest
-@RESPATH@/components/SecurityReporter.js
-
; ANGLE GLES-on-D3D rendering library
#ifdef MOZ_ANGLE_RENDERER
@BINPATH@/libEGL.dll
diff --git a/application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd b/application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd
index 1079c3cef..0fbd9cc35 100644
--- a/application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd
+++ b/application/basilisk/locales/en-US/chrome/browser/baseMenuOverlay.dtd
@@ -23,7 +23,7 @@
<!ENTITY helpKeyboardShortcuts.label "Keyboard Shortcuts">
<!ENTITY helpKeyboardShortcuts.accesskey "K">
-<!ENTITY helpSafeMode.label "Restart with Add-ons Disabled…">
+<!ENTITY helpSafeMode.label "Restart in Safe Mode…">
<!ENTITY helpSafeMode.accesskey "R">
<!ENTITY helpSafeMode.stop.label "Restart with Add-ons Enabled">
<!ENTITY helpSafeMode.stop.accesskey "R">
diff --git a/application/basilisk/locales/en-US/chrome/browser/browser.properties b/application/basilisk/locales/en-US/chrome/browser/browser.properties
index 8f4036dcd..aa7a82e4f 100644
--- a/application/basilisk/locales/en-US/chrome/browser/browser.properties
+++ b/application/basilisk/locales/en-US/chrome/browser/browser.properties
@@ -413,8 +413,8 @@ extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name=Default
extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description=The default theme.
# safeModeRestart
-safeModeRestartPromptTitle=Restart with Add-ons Disabled
-safeModeRestartPromptMessage=Are you sure you want to disable all add-ons and restart?
+safeModeRestartPromptTitle=Restart in Safe Mode
+safeModeRestartPromptMessage=Are you sure you want to restart in Safe Mode?
safeModeRestartButton=Restart
# LOCALIZATION NOTE (browser.menu.showCharacterEncoding): Set to the string
diff --git a/application/basilisk/locales/en-US/chrome/overrides/netError.dtd b/application/basilisk/locales/en-US/chrome/overrides/netError.dtd
index 6c65c9345..872847458 100644
--- a/application/basilisk/locales/en-US/chrome/overrides/netError.dtd
+++ b/application/basilisk/locales/en-US/chrome/overrides/netError.dtd
@@ -178,9 +178,6 @@ was trying to connect. -->
<!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">
-<!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites">
-<!ENTITY errorReporting.learnMore "Learn more…">
-
<!ENTITY remoteXUL.title "Remote XUL">
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
diff --git a/application/basilisk/modules/DirectoryLinksProvider.jsm b/application/basilisk/modules/DirectoryLinksProvider.jsm
new file mode 100644
index 000000000..117564099
--- /dev/null
+++ b/application/basilisk/modules/DirectoryLinksProvider.jsm
@@ -0,0 +1,1255 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = ["DirectoryLinksProvider"];
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+const ParserUtils = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils);
+
+Cu.importGlobalProperties(["XMLHttpRequest"]);
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+ "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
+ "resource://gre/modules/NewTabUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+ "resource://gre/modules/osfile.jsm")
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+ "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
+ "resource://gre/modules/UpdateUtils.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "eTLD",
+ "@mozilla.org/network/effective-tld-service;1",
+ "nsIEffectiveTLDService");
+XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => {
+ return new TextDecoder();
+});
+XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function () {
+ return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
+});
+XPCOMUtils.defineLazyGetter(this, "gUnicodeConverter", function () {
+ let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+ .createInstance(Ci.nsIScriptableUnicodeConverter);
+ converter.charset = 'utf8';
+ return converter;
+});
+
+
+// The filename where directory links are stored locally
+const DIRECTORY_LINKS_FILE = "directoryLinks.json";
+const DIRECTORY_LINKS_TYPE = "application/json";
+
+// The preference that tells whether to match the OS locale
+const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
+
+// The preference that tells what locale the user selected
+const PREF_SELECTED_LOCALE = "general.useragent.locale";
+
+// The preference that tells where to obtain directory links
+const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directory.source";
+
+// The preference that tells where to send click/view pings
+const PREF_DIRECTORY_PING = "browser.newtabpage.directory.ping";
+
+// The preference that tells if newtab is enhanced
+const PREF_NEWTAB_ENHANCED = "browser.newtabpage.enhanced";
+
+// Only allow link urls that are http(s)
+const ALLOWED_LINK_SCHEMES = new Set(["http", "https"]);
+
+// Only allow link image urls that are https or data
+const ALLOWED_IMAGE_SCHEMES = new Set(["https", "data"]);
+
+// Only allow urls to Mozilla's CDN or empty (for data URIs)
+const ALLOWED_URL_BASE = new Set(["mozilla.net", ""]);
+
+// The frecency of a directory link
+const DIRECTORY_FRECENCY = 1000;
+
+// The frecency of a suggested link
+const SUGGESTED_FRECENCY = Infinity;
+
+// The filename where frequency cap data stored locally
+const FREQUENCY_CAP_FILE = "frequencyCap.json";
+
+// Default settings for daily and total frequency caps
+const DEFAULT_DAILY_FREQUENCY_CAP = 3;
+const DEFAULT_TOTAL_FREQUENCY_CAP = 10;
+
+// Default timeDelta to prune unused frequency cap objects
+// currently set to 10 days in milliseconds
+const DEFAULT_PRUNE_TIME_DELTA = 10*24*60*60*1000;
+
+// The min number of visible (not blocked) history tiles to have before showing suggested tiles
+const MIN_VISIBLE_HISTORY_TILES = 8;
+
+// The max number of visible (not blocked) history tiles to test for inadjacency
+const MAX_VISIBLE_HISTORY_TILES = 15;
+
+// Allowed ping actions remotely stored as columns: case-insensitive [a-z0-9_]
+const PING_ACTIONS = ["block", "click", "pin", "sponsored", "sponsored_link", "unpin", "view"];
+
+// Location of inadjacent sites json
+const INADJACENCY_SOURCE = "chrome://browser/content/newtab/newTab.inadjacent.json";
+
+// Fake URL to keep track of last block of a suggested tile in the frequency cap object
+const FAKE_SUGGESTED_BLOCK_URL = "ignore://suggested_block";
+
+// Time before suggested tile is allowed to play again after block - default to 1 day
+const AFTER_SUGGESTED_BLOCK_DECAY_TIME = 24*60*60*1000;
+
+/**
+ * Singleton that serves as the provider of directory links.
+ * Directory links are a hard-coded set of links shown if a user's link
+ * inventory is empty.
+ */
+var DirectoryLinksProvider = {
+
+ __linksURL: null,
+
+ _observers: new Set(),
+
+ // links download deferred, resolved upon download completion
+ _downloadDeferred: null,
+
+ // download default interval is 24 hours in milliseconds
+ _downloadIntervalMS: 86400000,
+
+ /**
+ * A mapping from eTLD+1 to an enhanced link objects
+ */
+ _enhancedLinks: new Map(),
+
+ /**
+ * A mapping from site to a list of suggested link objects
+ */
+ _suggestedLinks: new Map(),
+
+ /**
+ * Frequency Cap object - maintains daily and total tile counts, and frequency cap settings
+ */
+ _frequencyCaps: {},
+
+ /**
+ * A set of top sites that we can provide suggested links for
+ */
+ _topSitesWithSuggestedLinks: new Set(),
+
+ /**
+ * lookup Set of inadjacent domains
+ */
+ _inadjacentSites: new Set(),
+
+ /**
+ * This flag is set if there is a suggested tile configured to avoid
+ * inadjacent sites in new tab
+ */
+ _avoidInadjacentSites: false,
+
+ /**
+ * This flag is set if _avoidInadjacentSites is true and there is
+ * an inadjacent site in the new tab
+ */
+ _newTabHasInadjacentSite: false,
+
+ get _observedPrefs() {
+ return Object.freeze({
+ enhanced: PREF_NEWTAB_ENHANCED,
+ linksURL: PREF_DIRECTORY_SOURCE,
+ matchOSLocale: PREF_MATCH_OS_LOCALE,
+ prefSelectedLocale: PREF_SELECTED_LOCALE,
+ });
+ },
+
+ get _linksURL() {
+ if (!this.__linksURL) {
+ try {
+ this.__linksURL = Services.prefs.getCharPref(this._observedPrefs["linksURL"]);
+ this.__linksURLModified = Services.prefs.prefHasUserValue(this._observedPrefs["linksURL"]);
+ }
+ catch (e) {
+ Cu.reportError("Error fetching directory links url from prefs: " + e);
+ }
+ }
+ return this.__linksURL;
+ },
+
+ /**
+ * Gets the currently selected locale for display.
+ * @return the selected locale or "en-US" if none is selected
+ */
+ get locale() {
+ let matchOS;
+ try {
+ matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
+ }
+ catch (e) {}
+
+ if (matchOS) {
+ return Services.locale.getLocaleComponentForUserAgent();
+ }
+
+ try {
+ let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE,
+ Ci.nsIPrefLocalizedString);
+ if (locale) {
+ return locale.data;
+ }
+ }
+ catch (e) {}
+
+ try {
+ return Services.prefs.getCharPref(PREF_SELECTED_LOCALE);
+ }
+ catch (e) {}
+
+ return "en-US";
+ },
+
+ /**
+ * Set appropriate default ping behavior controlled by enhanced pref
+ */
+ _setDefaultEnhanced: function DirectoryLinksProvider_setDefaultEnhanced() {
+ if (!Services.prefs.prefHasUserValue(PREF_NEWTAB_ENHANCED)) {
+ let enhanced = Services.prefs.getBoolPref(PREF_NEWTAB_ENHANCED);
+ try {
+ // Default to not enhanced if DNT is set to tell websites to not track
+ if (Services.prefs.getBoolPref("privacy.donottrackheader.enabled")) {
+ enhanced = false;
+ }
+ }
+ catch (ex) {}
+ Services.prefs.setBoolPref(PREF_NEWTAB_ENHANCED, enhanced);
+ }
+ },
+
+ observe: function DirectoryLinksProvider_observe(aSubject, aTopic, aData) {
+ if (aTopic == "nsPref:changed") {
+ switch (aData) {
+ // Re-set the default in case the user clears the pref
+ case this._observedPrefs.enhanced:
+ this._setDefaultEnhanced();
+ break;
+
+ case this._observedPrefs.linksURL:
+ delete this.__linksURL;
+ // fallthrough
+
+ // Force directory download on changes to fetch related prefs
+ case this._observedPrefs.matchOSLocale:
+ case this._observedPrefs.prefSelectedLocale:
+ this._fetchAndCacheLinksIfNecessary(true);
+ break;
+ }
+ }
+ },
+
+ _addPrefsObserver: function DirectoryLinksProvider_addObserver() {
+ for (let pref in this._observedPrefs) {
+ let prefName = this._observedPrefs[pref];
+ Services.prefs.addObserver(prefName, this, false);
+ }
+ },
+
+ _removePrefsObserver: function DirectoryLinksProvider_removeObserver() {
+ for (let pref in this._observedPrefs) {
+ let prefName = this._observedPrefs[pref];
+ Services.prefs.removeObserver(prefName, this);
+ }
+ },
+
+ _cacheSuggestedLinks: function(link) {
+ // Don't cache links that don't have the expected 'frecent_sites'
+ if (!link.frecent_sites) {
+ return;
+ }
+
+ for (let suggestedSite of link.frecent_sites) {
+ let suggestedMap = this._suggestedLinks.get(suggestedSite) || new Map();
+ suggestedMap.set(link.url, link);
+ this._setupStartEndTime(link);
+ this._suggestedLinks.set(suggestedSite, suggestedMap);
+ }
+ },
+
+ _fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
+ // Replace with the same display locale used for selecting links data
+ uri = uri.replace("%LOCALE%", this.locale);
+ uri = uri.replace("%CHANNEL%", UpdateUtils.UpdateChannel);
+
+ return this._downloadJsonData(uri).then(json => {
+ return OS.File.writeAtomic(this._directoryFilePath, json, {tmpPath: this._directoryFilePath + ".tmp"});
+ });
+ },
+
+ /**
+ * Downloads a links with json content
+ * @param download uri
+ * @return promise resolved to json string, "{}" returned if status != 200
+ */
+ _downloadJsonData: function DirectoryLinksProvider__downloadJsonData(uri) {
+ let deferred = Promise.defer();
+ let xmlHttp = this._newXHR();
+
+ xmlHttp.onload = function(aResponse) {
+ let json = this.responseText;
+ if (this.status && this.status != 200) {
+ json = "{}";
+ }
+ deferred.resolve(json);
+ };
+
+ xmlHttp.onerror = function(e) {
+ deferred.reject("Fetching " + uri + " results in error code: " + e.target.status);
+ };
+
+ try {
+ xmlHttp.open("GET", uri);
+ // Override the type so XHR doesn't complain about not well-formed XML
+ xmlHttp.overrideMimeType(DIRECTORY_LINKS_TYPE);
+ // Set the appropriate request type for servers that require correct types
+ xmlHttp.setRequestHeader("Content-Type", DIRECTORY_LINKS_TYPE);
+ xmlHttp.send();
+ } catch (e) {
+ deferred.reject("Error fetching " + uri);
+ Cu.reportError(e);
+ }
+ return deferred.promise;
+ },
+
+ /**
+ * Downloads directory links if needed
+ * @return promise resolved immediately if no download needed, or upon completion
+ */
+ _fetchAndCacheLinksIfNecessary: function DirectoryLinksProvider_fetchAndCacheLinksIfNecessary(forceDownload=false) {
+ if (this._downloadDeferred) {
+ // fetching links already - just return the promise
+ return this._downloadDeferred.promise;
+ }
+
+ if (forceDownload || this._needsDownload) {
+ this._downloadDeferred = Promise.defer();
+ this._fetchAndCacheLinks(this._linksURL).then(() => {
+ // the new file was successfully downloaded and cached, so update a timestamp
+ this._lastDownloadMS = Date.now();
+ this._downloadDeferred.resolve();
+ this._downloadDeferred = null;
+ this._callObservers("onManyLinksChanged")
+ },
+ error => {
+ this._downloadDeferred.resolve();
+ this._downloadDeferred = null;
+ this._callObservers("onDownloadFail");
+ });
+ return this._downloadDeferred.promise;
+ }
+
+ // download is not needed
+ return Promise.resolve();
+ },
+
+ /**
+ * @return true if download is needed, false otherwise
+ */
+ get _needsDownload () {
+ // fail if last download occured less then 24 hours ago
+ if ((Date.now() - this._lastDownloadMS) > this._downloadIntervalMS) {
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Create a new XMLHttpRequest that is anonymous, i.e., doesn't send cookies
+ */
+ _newXHR() {
+ return new XMLHttpRequest({mozAnon: true});
+ },
+
+ /**
+ * Reads directory links file and parses its content
+ * @return a promise resolved to an object with keys 'directory' and 'suggested',
+ * each containing a valid list of links,
+ * or {'directory': [], 'suggested': []} if read or parse fails.
+ */
+ _readDirectoryLinksFile: function DirectoryLinksProvider_readDirectoryLinksFile() {
+ let emptyOutput = {directory: [], suggested: [], enhanced: []};
+ return OS.File.read(this._directoryFilePath).then(binaryData => {
+ let output;
+ try {
+ let json = gTextDecoder.decode(binaryData);
+ let linksObj = JSON.parse(json);
+ output = {directory: linksObj.directory || [],
+ suggested: linksObj.suggested || [],
+ enhanced: linksObj.enhanced || []};
+ }
+ catch (e) {
+ Cu.reportError(e);
+ }
+ return output || emptyOutput;
+ },
+ error => {
+ Cu.reportError(error);
+ return emptyOutput;
+ });
+ },
+
+ /**
+ * Translates link.time_limits to UTC miliseconds and sets
+ * link.startTime and link.endTime properties in link object
+ */
+ _setupStartEndTime: function DirectoryLinksProvider_setupStartEndTime(link) {
+ // set start/end limits. Use ISO_8601 format: '2014-01-10T20:20:20.600Z'
+ // (details here http://en.wikipedia.org/wiki/ISO_8601)
+ // Note that if timezone is missing, FX will interpret as local time
+ // meaning that the server can sepecify any time, but if the capmaign
+ // needs to start at same time across multiple timezones, the server
+ // omits timezone indicator
+ if (!link.time_limits) {
+ return;
+ }
+
+ let parsedTime;
+ if (link.time_limits.start) {
+ parsedTime = Date.parse(link.time_limits.start);
+ if (parsedTime && !isNaN(parsedTime)) {
+ link.startTime = parsedTime;
+ }
+ }
+ if (link.time_limits.end) {
+ parsedTime = Date.parse(link.time_limits.end);
+ if (parsedTime && !isNaN(parsedTime)) {
+ link.endTime = parsedTime;
+ }
+ }
+ },
+
+ /*
+ * Handles campaign timeout
+ */
+ _onCampaignTimeout: function DirectoryLinksProvider_onCampaignTimeout() {
+ // _campaignTimeoutID is invalid here, so just set it to null
+ this._campaignTimeoutID = null;
+ this._updateSuggestedTile();
+ },
+
+ /*
+ * Clears capmpaign timeout
+ */
+ _clearCampaignTimeout: function DirectoryLinksProvider_clearCampaignTimeout() {
+ if (this._campaignTimeoutID) {
+ clearTimeout(this._campaignTimeoutID);
+ this._campaignTimeoutID = null;
+ }
+ },
+
+ /**
+ * Setup capmpaign timeout to recompute suggested tiles upon
+ * reaching soonest start or end time for the campaign
+ * @param timeout in milliseconds
+ */
+ _setupCampaignTimeCheck: function DirectoryLinksProvider_setupCampaignTimeCheck(timeout) {
+ // sanity check
+ if (!timeout || timeout <= 0) {
+ return;
+ }
+ this._clearCampaignTimeout();
+ // setup next timeout
+ this._campaignTimeoutID = setTimeout(this._onCampaignTimeout.bind(this), timeout);
+ },
+
+ /**
+ * Test link for campaign time limits: checks if link falls within start/end time
+ * and returns an object containing a use flag and the timeoutDate milliseconds
+ * when the link has to be re-checked for campaign start-ready or end-reach
+ * @param link
+ * @return object {use: true or false, timeoutDate: milliseconds or null}
+ */
+ _testLinkForCampaignTimeLimits: function DirectoryLinksProvider_testLinkForCampaignTimeLimits(link) {
+ let currentTime = Date.now();
+ // test for start time first
+ if (link.startTime && link.startTime > currentTime) {
+ // not yet ready for start
+ return {use: false, timeoutDate: link.startTime};
+ }
+ // otherwise check for end time
+ if (link.endTime) {
+ // passed end time
+ if (link.endTime <= currentTime) {
+ return {use: false};
+ }
+ // otherwise link is still ok, but we need to set timeoutDate
+ return {use: true, timeoutDate: link.endTime};
+ }
+ // if we are here, the link is ok and no timeoutDate needed
+ return {use: true};
+ },
+
+ /**
+ * Handles block on suggested tile: updates fake block url with current timestamp
+ */
+ handleSuggestedTileBlock: function DirectoryLinksProvider_handleSuggestedTileBlock() {
+ this._updateFrequencyCapSettings({url: FAKE_SUGGESTED_BLOCK_URL});
+ this._writeFrequencyCapFile();
+ this._updateSuggestedTile();
+ },
+
+ /**
+ * Checks if suggested tile is being blocked for the rest of "decay time"
+ * @return True if blocked, false otherwise
+ */
+ _isSuggestedTileBlocked: function DirectoryLinksProvider__isSuggestedTileBlocked() {
+ let capObject = this._frequencyCaps[FAKE_SUGGESTED_BLOCK_URL];
+ if (!capObject || !capObject.lastUpdated) {
+ // user never blocked suggested tile or lastUpdated is missing
+ return false;
+ }
+ // otherwise, make sure that enough time passed after suggested tile was blocked
+ return (capObject.lastUpdated + AFTER_SUGGESTED_BLOCK_DECAY_TIME) > Date.now();
+ },
+
+ /**
+ * Report some action on a newtab page (view, click)
+ * @param sites Array of sites shown on newtab page
+ * @param action String of the behavior to report
+ * @param triggeringSiteIndex optional Int index of the site triggering action
+ * @return download promise
+ */
+ reportSitesAction: function DirectoryLinksProvider_reportSitesAction(sites, action, triggeringSiteIndex) {
+ // Check if the suggested tile was shown
+ if (action == "view") {
+ sites.slice(0, triggeringSiteIndex + 1).filter(s => s).forEach(site => {
+ let {targetedSite, url} = site.link;
+ if (targetedSite) {
+ this._addFrequencyCapView(url);
+ }
+ });
+ }
+ // any click action on a suggested tile should stop that tile suggestion
+ // click/block - user either removed a tile or went to a landing page
+ // pin - tile turned into history tile, should no longer be suggested
+ // unpin - the tile was pinned before, should not matter
+ else {
+ // suggested tile has targetedSite, or frecent_sites if it was pinned
+ let {frecent_sites, targetedSite, url} = sites[triggeringSiteIndex].link;
+ if (frecent_sites || targetedSite) {
+ this._setFrequencyCapClick(url);
+ }
+ }
+
+ let newtabEnhanced = false;
+ let pingEndPoint = "";
+ try {
+ newtabEnhanced = Services.prefs.getBoolPref(PREF_NEWTAB_ENHANCED);
+ pingEndPoint = Services.prefs.getCharPref(PREF_DIRECTORY_PING);
+ }
+ catch (ex) {}
+
+ // Bug 1240245 - We no longer send pings, but frequency capping and fetching
+ // tests depend on the following actions, so references to PING remain.
+ let invalidAction = PING_ACTIONS.indexOf(action) == -1;
+ if (!newtabEnhanced || pingEndPoint == "" || invalidAction) {
+ return Promise.resolve();
+ }
+
+ return Task.spawn(function* () {
+ // since we updated views/clicks we need write _frequencyCaps to disk
+ yield this._writeFrequencyCapFile();
+ // Use this as an opportunity to potentially fetch new links
+ yield this._fetchAndCacheLinksIfNecessary();
+ }.bind(this));
+ },
+
+ /**
+ * Get the enhanced link object for a link (whether history or directory)
+ */
+ getEnhancedLink: function DirectoryLinksProvider_getEnhancedLink(link) {
+ // Use the provided link if it's already enhanced
+ return link.enhancedImageURI && link ? link :
+ this._enhancedLinks.get(NewTabUtils.extractSite(link.url));
+ },
+
+ /**
+ * Check if a url's scheme is in a Set of allowed schemes and if the base
+ * domain is allowed.
+ * @param url to check
+ * @param allowed Set of allowed schemes
+ * @param checkBase boolean to check the base domain
+ */
+ isURLAllowed(url, allowed, checkBase) {
+ // Assume no url is an allowed url
+ if (!url) {
+ return true;
+ }
+
+ let scheme = "", base = "";
+ try {
+ // A malformed url will not be allowed
+ let uri = Services.io.newURI(url, null, null);
+ scheme = uri.scheme;
+
+ // URIs without base domains will be allowed
+ base = Services.eTLD.getBaseDomain(uri);
+ }
+ catch (ex) {}
+ // Require a scheme match and the base only if desired
+ return allowed.has(scheme) && (!checkBase || ALLOWED_URL_BASE.has(base));
+ },
+
+ _escapeChars(text) {
+ let charMap = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ "'": '&#039;'
+ };
+
+ return text.replace(/[&<>"']/g, (character) => charMap[character]);
+ },
+
+ /**
+ * Gets the current set of directory links.
+ * @param aCallback The function that the array of links is passed to.
+ */
+ getLinks: function DirectoryLinksProvider_getLinks(aCallback) {
+ this._readDirectoryLinksFile().then(rawLinks => {
+ // Reset the cache of suggested tiles and enhanced images for this new set of links
+ this._enhancedLinks.clear();
+ this._suggestedLinks.clear();
+ this._clearCampaignTimeout();
+ this._avoidInadjacentSites = false;
+
+ // Only check base domain for images when using the default pref
+ let checkBase = !this.__linksURLModified;
+ let validityFilter = function(link) {
+ // Make sure the link url is allowed and images too if they exist
+ return this.isURLAllowed(link.url, ALLOWED_LINK_SCHEMES, false) &&
+ (!link.imageURI ||
+ this.isURLAllowed(link.imageURI, ALLOWED_IMAGE_SCHEMES, checkBase)) &&
+ (!link.enhancedImageURI ||
+ this.isURLAllowed(link.enhancedImageURI, ALLOWED_IMAGE_SCHEMES, checkBase));
+ }.bind(this);
+
+ rawLinks.suggested.filter(validityFilter).forEach((link, position) => {
+ // Suggested sites must have an adgroup name.
+ if (!link.adgroup_name) {
+ return;
+ }
+
+ let sanitizeFlags = ParserUtils.SanitizerCidEmbedsOnly |
+ ParserUtils.SanitizerDropForms |
+ ParserUtils.SanitizerDropNonCSSPresentation;
+
+ link.explanation = this._escapeChars(link.explanation ? ParserUtils.convertToPlainText(link.explanation, sanitizeFlags, 0) : "");
+ link.targetedName = this._escapeChars(ParserUtils.convertToPlainText(link.adgroup_name, sanitizeFlags, 0));
+ link.lastVisitDate = rawLinks.suggested.length - position;
+ // check if link wants to avoid inadjacent sites
+ if (link.check_inadjacency) {
+ this._avoidInadjacentSites = true;
+ }
+
+ // We cache suggested tiles here but do not push any of them in the links list yet.
+ // The decision for which suggested tile to include will be made separately.
+ this._cacheSuggestedLinks(link);
+ this._updateFrequencyCapSettings(link);
+ });
+
+ rawLinks.enhanced.filter(validityFilter).forEach((link, position) => {
+ link.lastVisitDate = rawLinks.enhanced.length - position;
+
+ // Stash the enhanced image for the site
+ if (link.enhancedImageURI) {
+ this._enhancedLinks.set(NewTabUtils.extractSite(link.url), link);
+ }
+ });
+
+ let links = rawLinks.directory.filter(validityFilter).map((link, position) => {
+ link.lastVisitDate = rawLinks.directory.length - position;
+ link.frecency = DIRECTORY_FRECENCY;
+ return link;
+ });
+
+ // Allow for one link suggestion on top of the default directory links
+ this.maxNumLinks = links.length + 1;
+
+ // prune frequency caps of outdated urls
+ this._pruneFrequencyCapUrls();
+ // write frequency caps object to disk asynchronously
+ this._writeFrequencyCapFile();
+
+ return links;
+ }).catch(ex => {
+ Cu.reportError(ex);
+ return [];
+ }).then(links => {
+ aCallback(links);
+ this._populatePlacesLinks();
+ });
+ },
+
+ init: function DirectoryLinksProvider_init() {
+ this._setDefaultEnhanced();
+ this._addPrefsObserver();
+ // setup directory file path and last download timestamp
+ this._directoryFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, DIRECTORY_LINKS_FILE);
+ this._lastDownloadMS = 0;
+
+ // setup frequency cap file path
+ this._frequencyCapFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, FREQUENCY_CAP_FILE);
+ // setup inadjacent sites URL
+ this._inadjacentSitesUrl = INADJACENCY_SOURCE;
+
+ NewTabUtils.placesProvider.addObserver(this);
+ NewTabUtils.links.addObserver(this);
+
+ return Task.spawn(function*() {
+ // get the last modified time of the links file if it exists
+ let doesFileExists = yield OS.File.exists(this._directoryFilePath);
+ if (doesFileExists) {
+ let fileInfo = yield OS.File.stat(this._directoryFilePath);
+ this._lastDownloadMS = Date.parse(fileInfo.lastModificationDate);
+ }
+ // read frequency cap file
+ yield this._readFrequencyCapFile();
+ // fetch directory on startup without force
+ yield this._fetchAndCacheLinksIfNecessary();
+ // fecth inadjacent sites on startup
+ yield this._loadInadjacentSites();
+ }.bind(this));
+ },
+
+ _handleManyLinksChanged: function() {
+ this._topSitesWithSuggestedLinks.clear();
+ this._suggestedLinks.forEach((suggestedLinks, site) => {
+ if (NewTabUtils.isTopPlacesSite(site)) {
+ this._topSitesWithSuggestedLinks.add(site);
+ }
+ });
+ this._updateSuggestedTile();
+ },
+
+ /**
+ * Updates _topSitesWithSuggestedLinks based on the link that was changed.
+ *
+ * @return true if _topSitesWithSuggestedLinks was modified, false otherwise.
+ */
+ _handleLinkChanged: function(aLink) {
+ let changedLinkSite = NewTabUtils.extractSite(aLink.url);
+ let linkStored = this._topSitesWithSuggestedLinks.has(changedLinkSite);
+
+ if (!NewTabUtils.isTopPlacesSite(changedLinkSite) && linkStored) {
+ this._topSitesWithSuggestedLinks.delete(changedLinkSite);
+ return true;
+ }
+
+ if (this._suggestedLinks.has(changedLinkSite) &&
+ NewTabUtils.isTopPlacesSite(changedLinkSite) && !linkStored) {
+ this._topSitesWithSuggestedLinks.add(changedLinkSite);
+ return true;
+ }
+
+ // always run _updateSuggestedTile if aLink is inadjacent
+ // and there are tiles configured to avoid it
+ if (this._avoidInadjacentSites && this._isInadjacentLink(aLink)) {
+ return true;
+ }
+
+ return false;
+ },
+
+ _populatePlacesLinks: function () {
+ NewTabUtils.links.populateProviderCache(NewTabUtils.placesProvider, () => {
+ this._handleManyLinksChanged();
+ });
+ },
+
+ onDeleteURI: function(aProvider, aLink) {
+ let {url} = aLink;
+ // remove clicked flag for that url and
+ // call observer upon disk write completion
+ this._removeTileClick(url).then(() => {
+ this._callObservers("onDeleteURI", url);
+ });
+ },
+
+ onClearHistory: function() {
+ // remove all clicked flags and call observers upon file write
+ this._removeAllTileClicks().then(() => {
+ this._callObservers("onClearHistory");
+ });
+ },
+
+ onLinkChanged: function (aProvider, aLink) {
+ // Make sure NewTabUtils.links handles the notification first.
+ setTimeout(() => {
+ if (this._handleLinkChanged(aLink) || this._shouldUpdateSuggestedTile()) {
+ this._updateSuggestedTile();
+ }
+ }, 0);
+ },
+
+ onManyLinksChanged: function () {
+ // Make sure NewTabUtils.links handles the notification first.
+ setTimeout(() => {
+ this._handleManyLinksChanged();
+ }, 0);
+ },
+
+ _getCurrentTopSiteCount: function() {
+ let visibleTopSiteCount = 0;
+ let newTabLinks = NewTabUtils.links.getLinks();
+ for (let link of newTabLinks.slice(0, MIN_VISIBLE_HISTORY_TILES)) {
+ // compute visibleTopSiteCount for suggested tiles
+ if (link && (link.type == "history" || link.type == "enhanced")) {
+ visibleTopSiteCount++;
+ }
+ }
+ // since newTabLinks are available, set _newTabHasInadjacentSite here
+ // note that _shouldUpdateSuggestedTile is called by _updateSuggestedTile
+ this._newTabHasInadjacentSite = this._avoidInadjacentSites && this._checkForInadjacentSites(newTabLinks);
+
+ return visibleTopSiteCount;
+ },
+
+ _shouldUpdateSuggestedTile: function() {
+ let sortedLinks = NewTabUtils.getProviderLinks(this);
+
+ let mostFrecentLink = {};
+ if (sortedLinks && sortedLinks.length) {
+ mostFrecentLink = sortedLinks[0]
+ }
+
+ let currTopSiteCount = this._getCurrentTopSiteCount();
+ if ((!mostFrecentLink.targetedSite && currTopSiteCount >= MIN_VISIBLE_HISTORY_TILES) ||
+ (mostFrecentLink.targetedSite && currTopSiteCount < MIN_VISIBLE_HISTORY_TILES)) {
+ // If mostFrecentLink has a targetedSite then mostFrecentLink is a suggested link.
+ // If we have enough history links (8+) to show a suggested tile and we are not
+ // already showing one, then we should update (to *attempt* to add a suggested tile).
+ // OR if we don't have enough history to show a suggested tile (<8) and we are
+ // currently showing one, we should update (to remove it).
+ return true;
+ }
+
+ return false;
+ },
+
+ /**
+ * Chooses and returns a suggested tile based on a user's top sites
+ * that we have an available suggested tile for.
+ *
+ * @return the chosen suggested tile, or undefined if there isn't one
+ */
+ _updateSuggestedTile: function() {
+ let sortedLinks = NewTabUtils.getProviderLinks(this);
+
+ if (!sortedLinks) {
+ // If NewTabUtils.links.resetCache() is called before getting here,
+ // sortedLinks may be undefined.
+ return undefined;
+ }
+
+ // Delete the current suggested tile, if one exists.
+ let initialLength = sortedLinks.length;
+ if (initialLength) {
+ let mostFrecentLink = sortedLinks[0];
+ if (mostFrecentLink.targetedSite) {
+ this._callObservers("onLinkChanged", {
+ url: mostFrecentLink.url,
+ frecency: SUGGESTED_FRECENCY,
+ lastVisitDate: mostFrecentLink.lastVisitDate,
+ type: mostFrecentLink.type,
+ }, 0, true);
+ }
+ }
+
+ if (this._topSitesWithSuggestedLinks.size == 0 ||
+ !this._shouldUpdateSuggestedTile() ||
+ this._isSuggestedTileBlocked()) {
+ // There are no potential suggested links we can show or not
+ // enough history for a suggested tile, or suggested tile was
+ // recently blocked and wait time interval has not decayed yet
+ return undefined;
+ }
+
+ // Create a flat list of all possible links we can show as suggested.
+ // Note that many top sites may map to the same suggested links, but we only
+ // want to count each suggested link once (based on url), thus possibleLinks is a map
+ // from url to suggestedLink. Thus, each link has an equal chance of being chosen at
+ // random from flattenedLinks if it appears only once.
+ let nextTimeout;
+ let possibleLinks = new Map();
+ let targetedSites = new Map();
+ this._topSitesWithSuggestedLinks.forEach(topSiteWithSuggestedLink => {
+ let suggestedLinksMap = this._suggestedLinks.get(topSiteWithSuggestedLink);
+ suggestedLinksMap.forEach((suggestedLink, url) => {
+ // Skip this link if we've shown it too many times already
+ if (!this._testFrequencyCapLimits(url)) {
+ return;
+ }
+
+ // as we iterate suggestedLinks, check for campaign start/end
+ // time limits, and set nextTimeout to the closest timestamp
+ let {use, timeoutDate} = this._testLinkForCampaignTimeLimits(suggestedLink);
+ // update nextTimeout is necessary
+ if (timeoutDate && (!nextTimeout || nextTimeout > timeoutDate)) {
+ nextTimeout = timeoutDate;
+ }
+ // Skip link if it falls outside campaign time limits
+ if (!use) {
+ return;
+ }
+
+ // Skip link if it avoids inadjacent sites and newtab has one
+ if (suggestedLink.check_inadjacency && this._newTabHasInadjacentSite) {
+ return;
+ }
+
+ possibleLinks.set(url, suggestedLink);
+
+ // Keep a map of URL to targeted sites. We later use this to show the user
+ // what site they visited to trigger this suggestion.
+ if (!targetedSites.get(url)) {
+ targetedSites.set(url, []);
+ }
+ targetedSites.get(url).push(topSiteWithSuggestedLink);
+ })
+ });
+
+ // setup timeout check for starting or ending campaigns
+ if (nextTimeout) {
+ this._setupCampaignTimeCheck(nextTimeout - Date.now());
+ }
+
+ // We might have run out of possible links to show
+ let numLinks = possibleLinks.size;
+ if (numLinks == 0) {
+ return undefined;
+ }
+
+ let flattenedLinks = [...possibleLinks.values()];
+
+ // Choose our suggested link at random
+ let suggestedIndex = Math.floor(Math.random() * numLinks);
+ let chosenSuggestedLink = flattenedLinks[suggestedIndex];
+
+ // Add the suggested link to the front with some extra values
+ this._callObservers("onLinkChanged", Object.assign({
+ frecency: SUGGESTED_FRECENCY,
+
+ // Choose the first site a user has visited as the target. In the future,
+ // this should be the site with the highest frecency. However, we currently
+ // store frecency by URL not by site.
+ targetedSite: targetedSites.get(chosenSuggestedLink.url).length ?
+ targetedSites.get(chosenSuggestedLink.url)[0] : null
+ }, chosenSuggestedLink));
+ return chosenSuggestedLink;
+ },
+
+ /**
+ * Loads inadjacent sites
+ * @return a promise resolved when lookup Set for sites is built
+ */
+ _loadInadjacentSites: function DirectoryLinksProvider_loadInadjacentSites() {
+ return this._downloadJsonData(this._inadjacentSitesUrl).then(jsonString => {
+ let jsonObject = {};
+ try {
+ jsonObject = JSON.parse(jsonString);
+ }
+ catch (e) {
+ Cu.reportError(e);
+ }
+
+ this._inadjacentSites = new Set(jsonObject.domains);
+ });
+ },
+
+ /**
+ * Genegrates hash suitable for looking up inadjacent site
+ * @param value to hsh
+ * @return hased value, base64-ed
+ */
+ _generateHash: function DirectoryLinksProvider_generateHash(value) {
+ let byteArr = gUnicodeConverter.convertToByteArray(value);
+ gCryptoHash.init(gCryptoHash.MD5);
+ gCryptoHash.update(byteArr, byteArr.length);
+ return gCryptoHash.finish(true);
+ },
+
+ /**
+ * Checks if link belongs to inadjacent domain
+ * @param link to check
+ * @return true for inadjacent domains, false otherwise
+ */
+ _isInadjacentLink: function DirectoryLinksProvider_isInadjacentLink(link) {
+ let baseDomain = link.baseDomain || NewTabUtils.extractSite(link.url || "");
+ if (!baseDomain) {
+ return false;
+ }
+ // check if hashed domain is inadjacent
+ return this._inadjacentSites.has(this._generateHash(baseDomain));
+ },
+
+ /**
+ * Checks if new tab has inadjacent site
+ * @param new tab links (or nothing, in which case NewTabUtils.links.getLinks() is called
+ * @return true if new tab shows has inadjacent site
+ */
+ _checkForInadjacentSites: function DirectoryLinksProvider_checkForInadjacentSites(newTabLink) {
+ let links = newTabLink || NewTabUtils.links.getLinks();
+ for (let link of links.slice(0, MAX_VISIBLE_HISTORY_TILES)) {
+ // check links against inadjacent list - specifically include ALL link types
+ if (this._isInadjacentLink(link)) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Reads json file, parses its content, and returns resulting object
+ * @param json file path
+ * @param json object to return in case file read or parse fails
+ * @return a promise resolved to a valid object or undefined upon error
+ */
+ _readJsonFile: Task.async(function* (filePath, nullObject) {
+ let jsonObj;
+ try {
+ let binaryData = yield OS.File.read(filePath);
+ let json = gTextDecoder.decode(binaryData);
+ jsonObj = JSON.parse(json);
+ }
+ catch (e) {}
+ return jsonObj || nullObject;
+ }),
+
+ /**
+ * Loads frequency cap object from file and parses its content
+ * @return a promise resolved upon load completion
+ * on error or non-exstent file _frequencyCaps is set to empty object
+ */
+ _readFrequencyCapFile: Task.async(function* () {
+ // set _frequencyCaps object to file's content or empty object
+ this._frequencyCaps = yield this._readJsonFile(this._frequencyCapFilePath, {});
+ }),
+
+ /**
+ * Saves frequency cap object to file
+ * @return a promise resolved upon file i/o completion
+ */
+ _writeFrequencyCapFile: function DirectoryLinksProvider_writeFrequencyCapFile() {
+ let json = JSON.stringify(this._frequencyCaps || {});
+ return OS.File.writeAtomic(this._frequencyCapFilePath, json, {tmpPath: this._frequencyCapFilePath + ".tmp"});
+ },
+
+ /**
+ * Clears frequency cap object and writes empty json to file
+ * @return a promise resolved upon file i/o completion
+ */
+ _clearFrequencyCap: function DirectoryLinksProvider_clearFrequencyCap() {
+ this._frequencyCaps = {};
+ return this._writeFrequencyCapFile();
+ },
+
+ /**
+ * updates frequency cap configuration for a link
+ */
+ _updateFrequencyCapSettings: function DirectoryLinksProvider_updateFrequencyCapSettings(link) {
+ let capsObject = this._frequencyCaps[link.url];
+ if (!capsObject) {
+ // create an object with empty counts
+ capsObject = {
+ dailyViews: 0,
+ totalViews: 0,
+ lastShownDate: 0,
+ };
+ this._frequencyCaps[link.url] = capsObject;
+ }
+ // set last updated timestamp
+ capsObject.lastUpdated = Date.now();
+ // check for link configuration
+ if (link.frequency_caps) {
+ capsObject.dailyCap = link.frequency_caps.daily || DEFAULT_DAILY_FREQUENCY_CAP;
+ capsObject.totalCap = link.frequency_caps.total || DEFAULT_TOTAL_FREQUENCY_CAP;
+ }
+ else {
+ // fallback to defaults
+ capsObject.dailyCap = DEFAULT_DAILY_FREQUENCY_CAP;
+ capsObject.totalCap = DEFAULT_TOTAL_FREQUENCY_CAP;
+ }
+ },
+
+ /**
+ * Prunes frequency cap objects for outdated links
+ * @param timeDetla milliseconds
+ * all cap objects with lastUpdated less than (now() - timeDelta)
+ * will be removed. This is done to remove frequency cap objects
+ * for unused tile urls
+ */
+ _pruneFrequencyCapUrls: function DirectoryLinksProvider_pruneFrequencyCapUrls(timeDelta = DEFAULT_PRUNE_TIME_DELTA) {
+ let timeThreshold = Date.now() - timeDelta;
+ Object.keys(this._frequencyCaps).forEach(url => {
+ // remove url if it is not ignorable and wasn't updated for a while
+ if (!url.startsWith("ignore") && this._frequencyCaps[url].lastUpdated <= timeThreshold) {
+ delete this._frequencyCaps[url];
+ }
+ });
+ },
+
+ /**
+ * Checks if supplied timestamp happened today
+ * @param timestamp in milliseconds
+ * @return true if the timestamp was made today, false otherwise
+ */
+ _wasToday: function DirectoryLinksProvider_wasToday(timestamp) {
+ let showOn = new Date(timestamp);
+ let today = new Date();
+ // call timestamps identical if both day and month are same
+ return showOn.getDate() == today.getDate() &&
+ showOn.getMonth() == today.getMonth() &&
+ showOn.getYear() == today.getYear();
+ },
+
+ /**
+ * adds some number of views for a url
+ * @param url String url of the suggested link
+ */
+ _addFrequencyCapView: function DirectoryLinksProvider_addFrequencyCapView(url) {
+ let capObject = this._frequencyCaps[url];
+ // sanity check
+ if (!capObject) {
+ return;
+ }
+
+ // if the day is new: reset the daily counter and lastShownDate
+ if (!this._wasToday(capObject.lastShownDate)) {
+ capObject.dailyViews = 0;
+ // update lastShownDate
+ capObject.lastShownDate = Date.now();
+ }
+
+ // bump both daily and total counters
+ capObject.totalViews++;
+ capObject.dailyViews++;
+
+ // if any of the caps is reached - update suggested tiles
+ if (capObject.totalViews >= capObject.totalCap ||
+ capObject.dailyViews >= capObject.dailyCap) {
+ this._updateSuggestedTile();
+ }
+ },
+
+ /**
+ * Sets clicked flag for link url
+ * @param url String url of the suggested link
+ */
+ _setFrequencyCapClick(url) {
+ let capObject = this._frequencyCaps[url];
+ // sanity check
+ if (!capObject) {
+ return;
+ }
+ capObject.clicked = true;
+ // and update suggested tiles, since current tile became invalid
+ this._updateSuggestedTile();
+ },
+
+ /**
+ * Tests frequency cap limits for link url
+ * @param url String url of the suggested link
+ * @return true if link is viewable, false otherwise
+ */
+ _testFrequencyCapLimits: function DirectoryLinksProvider_testFrequencyCapLimits(url) {
+ let capObject = this._frequencyCaps[url];
+ // sanity check: if url is missing - do not show this tile
+ if (!capObject) {
+ return false;
+ }
+
+ // check for clicked set or total views reached
+ if (capObject.clicked || capObject.totalViews >= capObject.totalCap) {
+ return false;
+ }
+
+ // otherwise check if link is over daily views limit
+ if (this._wasToday(capObject.lastShownDate) &&
+ capObject.dailyViews >= capObject.dailyCap) {
+ return false;
+ }
+
+ // we passed all cap tests: return true
+ return true;
+ },
+
+ /**
+ * Removes clicked flag from frequency cap entry for tile landing url
+ * @param url String url of the suggested link
+ * @return promise resolved upon disk write completion
+ */
+ _removeTileClick: function DirectoryLinksProvider_removeTileClick(url = "") {
+ // remove trailing slash, to accomodate Places sending site urls ending with '/'
+ let noTrailingSlashUrl = url.replace(/\/$/, "");
+ let capObject = this._frequencyCaps[url] || this._frequencyCaps[noTrailingSlashUrl];
+ // return resolved promise if capObject is not found
+ if (!capObject) {
+ return Promise.resolve();
+ }
+ // otherwise remove clicked flag
+ delete capObject.clicked;
+ return this._writeFrequencyCapFile();
+ },
+
+ /**
+ * Removes all clicked flags from frequency cap object
+ * @return promise resolved upon disk write completion
+ */
+ _removeAllTileClicks: function DirectoryLinksProvider_removeAllTileClicks() {
+ Object.keys(this._frequencyCaps).forEach(url => {
+ delete this._frequencyCaps[url].clicked;
+ });
+ return this._writeFrequencyCapFile();
+ },
+
+ /**
+ * Return the object to its pre-init state
+ */
+ reset: function DirectoryLinksProvider_reset() {
+ delete this.__linksURL;
+ this._removePrefsObserver();
+ this._removeObservers();
+ },
+
+ addObserver: function DirectoryLinksProvider_addObserver(aObserver) {
+ this._observers.add(aObserver);
+ },
+
+ removeObserver: function DirectoryLinksProvider_removeObserver(aObserver) {
+ this._observers.delete(aObserver);
+ },
+
+ _callObservers(methodName, ...args) {
+ for (let obs of this._observers) {
+ if (typeof(obs[methodName]) == "function") {
+ try {
+ obs[methodName](this, ...args);
+ } catch (err) {
+ Cu.reportError(err);
+ }
+ }
+ }
+ },
+
+ _removeObservers: function() {
+ this._observers.clear();
+ }
+};
diff --git a/application/basilisk/modules/moz.build b/application/basilisk/modules/moz.build
index cd8f2ce62..d043d4799 100644
--- a/application/basilisk/modules/moz.build
+++ b/application/basilisk/modules/moz.build
@@ -16,6 +16,7 @@ EXTRA_JS_MODULES += [
'ContentObservers.jsm',
'ContentSearch.jsm',
'ContentWebRTC.jsm',
+ 'DirectoryLinksProvider.jsm',
'E10SUtils.jsm',
'Feeds.jsm',
'FormSubmitObserver.jsm',
diff --git a/application/palemoon/base/content/newtab/grid.js b/application/palemoon/base/content/newtab/grid.js
index be5a57c4b..db3d319c3 100644
--- a/application/palemoon/base/content/newtab/grid.js
+++ b/application/palemoon/base/content/newtab/grid.js
@@ -5,12 +5,6 @@
#endif
/**
- * Define various fixed dimensions
- */
-const GRID_BOTTOM_EXTRA = 7; // title's line-height extends 7px past the margin
-const GRID_WIDTH_EXTRA = 1; // provide 1px buffer to allow for rounding error
-
-/**
* This singleton represents the grid that contains all sites.
*/
var gGrid = {
@@ -35,7 +29,14 @@ var gGrid = {
/**
* All sites contained in the grid's cells. Sites may be empty.
*/
- get sites() { return [for (cell of this.cells) cell.site]; },
+ get sites() {
+ // return [for (cell of this.cells) cell.site];
+ let aSites = [];
+ for (let cell of this.cells) {
+ aSites.push(cell.site);
+ }
+ return aSites;
+ },
// Tells whether the grid has already been initialized.
get ready() { return !!this._ready; },
@@ -55,20 +56,7 @@ var gGrid = {
gLinks.populateCache(() => {
this._refreshGrid();
this._ready = true;
-
- // If fetching links took longer than loading the page itself then
- // we need to resize the grid as that was blocked until now.
- // We also want to resize now if the page was already loaded when
- // initializing the grid (the user toggled the page).
- this._resizeGrid();
-
- addEventListener("resize", this);
});
-
- // Resize the grid as soon as the page loads.
- if (!this.isDocumentLoaded) {
- addEventListener("load", this);
- }
},
/**
@@ -87,12 +75,7 @@ var gGrid = {
* Handles all grid events.
*/
handleEvent: function Grid_handleEvent(aEvent) {
- switch (aEvent.type) {
- case "load":
- case "resize":
- this._resizeGrid();
- break;
- }
+ // Any specific events should go here.
},
/**
@@ -110,31 +93,37 @@ var gGrid = {
},
/**
- * Renders and resizes the gird. _resizeGrid() call is needed to ensure
- * that scrollbar disappears when the bottom row becomes empty following
- * the block action, or tile display is turmed off via cog menu
+ * Renders the grid.
*/
-
refresh() {
this._refreshGrid();
- this._resizeGrid();
},
/**
* Renders the grid, including cells and sites.
*/
_refreshGrid() {
+ let row = document.createElementNS(HTML_NAMESPACE, "div");
+ row.classList.add("newtab-row");
let cell = document.createElementNS(HTML_NAMESPACE, "div");
cell.classList.add("newtab-cell");
- // Creates all the cells up to the maximum
- let fragment = document.createDocumentFragment();
- for (let i = 0; i < gGridPrefs.gridColumns * gGridPrefs.gridRows; i++) {
- fragment.appendChild(cell.cloneNode(true));
+ // Clear the grid
+ this._node.innerHTML = "";
+
+ // Creates the structure of one row
+ for (let i = 0; i < gGridPrefs.gridColumns; i++) {
+ row.appendChild(cell.cloneNode(true));
}
- // Create cells.
- let cells = Array.from(fragment.childNodes, (cell) => new Cell(this, cell));
+ // Creates the grid
+ for (let j = 0; j < gGridPrefs.gridRows; j++) {
+ this._node.appendChild(row.cloneNode(true));
+ }
+
+ // Create cell array.
+ let cellElements = this.node.querySelectorAll(".newtab-cell");
+ let cells = Array.from(cellElements, (cell) => new Cell(this, cell));
// Fetch links.
let links = gLinks.getLinks();
@@ -152,20 +141,6 @@ var gGrid = {
}
this._cells = cells;
- while (this._gridDefaultContent.nextSibling) {
- this._gridDefaultContent.nextSibling.remove();
- }
- this._node.appendChild(fragment);
- },
-
- /**
- * Calculate the height for a number of rows up to the maximum rows
- * @param rows Number of rows defaulting to the max
- */
- _computeHeight: function Grid_computeHeight(aRows) {
- let {gridRows} = gGridPrefs;
- aRows = aRows === undefined ? gridRows : Math.min(gridRows, aRows);
- return aRows * this._cellHeight + GRID_BOTTOM_EXTRA;
},
/**
@@ -199,74 +174,6 @@ var gGrid = {
_isHistoricalTile: function Grid_isHistoricalTile(aPos) {
let site = this.sites[aPos];
return site && (site.isPinned() || site.link && site.link.type == "history");
- },
-
- /**
- * Make sure the correct number of rows and columns are visible
- */
- _resizeGrid: function Grid_resizeGrid() {
- // If we're somehow called before the page has finished loading,
- // let's bail out to avoid caching zero heights and widths.
- // We'll be called again when DOMContentLoaded fires.
- // Same goes for the grid if that's not ready yet.
- if (!this.isDocumentLoaded || !this._ready) {
- return;
- }
-
- // Save the cell's computed height/width including margin and border
- if (this._cellHeight === undefined) {
- let refCell = document.querySelector(".newtab-cell");
- let style = getComputedStyle(refCell);
- this._cellHeight = refCell.offsetHeight +
- parseFloat(style.marginTop) + parseFloat(style.marginBottom);
- this._cellWidth = refCell.offsetWidth +
- parseFloat(style.marginLeft) + parseFloat(style.marginRight);
- }
-
- let searchContainer = document.querySelector("#searchContainer");
- // Save search-container margin height
- if (this._searchContainerMargin === undefined) {
- let style = getComputedStyle(searchContainer);
- this._searchContainerMargin = parseFloat(style.marginBottom) +
- parseFloat(style.marginTop);
- }
-
- // Find the number of rows we can place into view port
- let availHeight = document.documentElement.clientHeight -
- searchContainer.offsetHeight - this._searchContainerMargin;
- let visibleRows = Math.floor(availHeight / this._cellHeight);
-
- // Find the number of columns that fit into view port
- let maxGridWidth = gGridPrefs.gridColumns * this._cellWidth + GRID_WIDTH_EXTRA;
- // available width is current grid width, but no greater than maxGridWidth
- let availWidth = Math.min(document.querySelector("#newtab-grid").clientWidth,
- maxGridWidth);
- // finally get the number of columns we can fit into view port
- let gridColumns = Math.floor(availWidth / this._cellWidth);
- // walk sites backwords until a pinned or history tile is found or visibleRows reached
- let tileIndex = Math.min(gGridPrefs.gridRows * gridColumns, this.sites.length) - 1;
- while (tileIndex >= visibleRows * gridColumns) {
- if (this._isHistoricalTile(tileIndex)) {
- break;
- }
- tileIndex--;
- }
-
- // Compute the actual number of grid rows we will display (potentially
- // with a scroll bar). tileIndex now points to a historical tile with
- // heighest index or to the last index of the visible row, if none found
- // Dividing tileIndex by number of tiles in a column gives the rows
- let gridRows = Math.floor(tileIndex / gridColumns) + 1;
-
- // we need to set grid width, for otherwise the scrollbar may shrink
- // the grid when shown and cause grid layout to be different from
- // what being computed above. This, in turn, may cause scrollbar shown
- // for directory tiles, and introduce jitter when grid width is aligned
- // exactly on the column boundary
- this._node.style.width = gridColumns * this._cellWidth + "px";
- this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth +
- GRID_WIDTH_EXTRA + "px";
- this._node.style.height = this._computeHeight() + "px";
- this._node.style.maxHeight = this._computeHeight(gridRows) + "px";
}
+
};
diff --git a/application/palemoon/base/content/newtab/newTab.css b/application/palemoon/base/content/newtab/newTab.css
index a5431cf65..fe745d2fd 100644
--- a/application/palemoon/base/content/newtab/newTab.css
+++ b/application/palemoon/base/content/newtab/newTab.css
@@ -42,6 +42,18 @@ input[type=button] {
pointer-events: none;
}
+/* TOGGLE */
+#newtab-toggle {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+}
+
+#newtab-toggle:-moz-locale-dir(rtl) {
+ left: 12px;
+ right: auto;
+}
+
/* MARGINS */
#newtab-vertical-margin {
display: -moz-box;
@@ -69,33 +81,38 @@ input[type=button] {
#newtab-horizontal-margin {
display: -moz-box;
- -moz-box-flex: 1;
-}
-
-#newtab-margin-top,
-#newtab-margin-bottom {
- display: -moz-box;
- position: relative;
+ -moz-box-flex: 5;
}
#newtab-margin-top {
+ min-height: 10px;
+ max-height: 30px;
+ display: -moz-box;
-moz-box-flex: 1;
+ -moz-box-align: center;
+ -moz-box-pack: center;
}
#newtab-margin-bottom {
- -moz-box-flex: 2;
+ min-height: 40px;
+ max-height: 80px;
+ -moz-box-flex: 1;
}
.newtab-side-margin {
- min-width: 10px;
+ min-width: 40px;
+ max-width: 300px;
-moz-box-flex: 1;
}
/* GRID */
#newtab-grid {
+ display: -moz-box;
-moz-box-flex: 5;
- overflow: hidden;
- transition: 300ms ease-out;
+ -moz-box-orient: vertical;
+ min-width: 600px;
+ min-height: 400px;
+ transition: 175ms ease-out;
transition-property: opacity;
}
@@ -108,25 +125,30 @@ input[type=button] {
pointer-events: none;
}
+/* ROWS */
+.newtab-row {
+ display: -moz-box;
+ -moz-box-orient: horizontal;
+ -moz-box-direction: normal;
+ -moz-box-flex: 1;
+}
+
/*
- * If you change the sizes here, make sure you
- * change the preferences:
+ * Thumbnail image sizes are determined in the preferences:
* toolkit.pageThumbs.minWidth
* toolkit.pageThumbs.minHeight
*/
/* CELLS */
.newtab-cell {
display: -moz-box;
- height: 180px;
- margin: 15px 10px 30px;
- width: 250px;
+ -moz-box-flex: 1;
}
/* SITES */
.newtab-site {
position: relative;
-moz-box-flex: 1;
- transition: 200ms ease-out;
+ transition: 150ms ease-out;
transition-property: top, left, opacity;
}
@@ -211,7 +233,7 @@ input[type=button] {
display: -moz-box;
position: relative;
-moz-box-pack: center;
- margin: 40px 0 15px;
+ margin: 10px 0 15px;
}
#searchContainer[page-disabled] {
diff --git a/application/palemoon/base/content/newtab/newTab.xhtml b/application/palemoon/base/content/newtab/newTab.xhtml
index eac62c987..de000e723 100644
--- a/application/palemoon/base/content/newtab/newTab.xhtml
+++ b/application/palemoon/base/content/newtab/newTab.xhtml
@@ -54,6 +54,7 @@
</div>
<div id="newtab-margin-bottom"/>
+ <input id="newtab-toggle" type="button"/>
</div>
</body>
<script type="text/javascript;version=1.8" src="chrome://browser/content/newtab/newTab.js"/>
diff --git a/application/palemoon/base/content/newtab/page.js b/application/palemoon/base/content/newtab/page.js
index cbd6750b6..7117d4527 100644
--- a/application/palemoon/base/content/newtab/page.js
+++ b/application/palemoon/base/content/newtab/page.js
@@ -21,6 +21,10 @@ var gPage = {
// Listen for 'unload' to unregister this page.
addEventListener("unload", this, false);
+
+ // Listen for toggle button clicks.
+ let button = document.getElementById("newtab-toggle");
+ button.addEventListener("click", e => this.toggleEnabled(e));
// XXX bug 991111 - Not all click events are correctly triggered when
// listening from xhtml nodes -- in particular middle clicks on sites, so
@@ -277,6 +281,11 @@ var gPage = {
}
},
+ toggleEnabled: function(aEvent) {
+ gAllPages.enabled = !gAllPages.enabled;
+ event.stopPropagation();
+ },
+
maybeShowAutoMigrationUndoNotification() {
// sendAsyncMessage("NewTab:MaybeShowAutoMigrationUndoNotification");
},
diff --git a/application/palemoon/base/content/palemoon.xhtml b/application/palemoon/base/content/palemoon.xhtml
new file mode 100644
index 000000000..96757052c
--- /dev/null
+++ b/application/palemoon/base/content/palemoon.xhtml
@@ -0,0 +1,66 @@
+<!DOCTYPE html
+[
+ <!ENTITY % mozillaDTD SYSTEM "chrome://browser/locale/palemoon.dtd" >
+ %mozillaDTD;
+ <!ENTITY % directionDTD SYSTEM "chrome://global/locale/global.dtd" >
+ %directionDTD;
+]>
+
+<!-- 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/. -->
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta charset='utf-8' />
+ <title>&chronicles.title.55.2;</title>
+
+<style type="text/css">
+html {
+ background: #333399 radial-gradient( circle at 75% 25%, #6666b0 0%, #333399 40%, #111177 80%) center center / cover no-repeat;
+ color: white;
+ font-style: italic;
+ text-rendering: optimizeLegibility;
+ min-height: 100%;
+}
+
+#moztext {
+ margin-top: 15%;
+ font-size: 1.1em;
+ font-family: serif;
+ text-align: center;
+ line-height: 1.5;
+}
+
+#from {
+ font-size: 1.95em;
+ font-family: serif;
+ text-align: right;
+}
+
+em {
+ font-size: 1.3em;
+ line-height: 0;
+}
+
+a {
+ text-decoration: none;
+ color: white;
+}
+</style>
+</head>
+
+<body dir="&locale.dir;">
+
+<section>
+ <p id="moztext">
+ &chronicles.quote.55.2;
+ </p>
+
+ <p id="from">
+ &chronicles.from.55.2;
+ </p>
+</section>
+
+</body>
+</html>
diff --git a/application/palemoon/base/content/sanitize.js b/application/palemoon/base/content/sanitize.js
index 74372a4af..0c85fa215 100644
--- a/application/palemoon/base/content/sanitize.js
+++ b/application/palemoon/base/content/sanitize.js
@@ -11,7 +11,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
"resource://gre/modules/Downloads.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
- "resource:///modules/promise.js");
+ "resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
diff --git a/application/palemoon/base/content/utilityOverlay.js b/application/palemoon/base/content/utilityOverlay.js
index c45297e0b..63488e209 100644
--- a/application/palemoon/base/content/utilityOverlay.js
+++ b/application/palemoon/base/content/utilityOverlay.js
@@ -250,6 +250,10 @@ function openLinkIn(url, where, params) {
aRelatedToCurrent = false;
}
+ // We can only do this after we're sure of what |w| will be the rest of this function.
+ // Note that if |w| is null we might have no current browser (we'll open a new window).
+ var aCurrentBrowser = params.currentBrowser || (w && w.gBrowser.selectedBrowser);
+
if (!w || where == "window") {
// This propagates to window.arguments.
// Strip referrer data when opening a new private window, to prevent
diff --git a/application/palemoon/base/jar.mn b/application/palemoon/base/jar.mn
index 246cf9017..d8c3f4b21 100644
--- a/application/palemoon/base/jar.mn
+++ b/application/palemoon/base/jar.mn
@@ -69,6 +69,7 @@ browser.jar:
content/browser/padlock_classic_https.png (content/padlock_classic_https.png)
content/browser/padlock_classic_low.png (content/padlock_classic_low.png)
content/browser/padlock_classic_broken.png (content/padlock_classic_broken.png)
+ content/browser/palemoon.xhtml (content/palemoon.xhtml)
content/browser/newtab/newTab.xhtml (content/newtab/newTab.xhtml)
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
content/browser/newtab/newTab.css (content/newtab/newTab.css)
diff --git a/application/palemoon/components/about/AboutRedirector.cpp b/application/palemoon/components/about/AboutRedirector.cpp
index 7e4c634f7..508202c7d 100644
--- a/application/palemoon/components/about/AboutRedirector.cpp
+++ b/application/palemoon/components/about/AboutRedirector.cpp
@@ -57,7 +57,7 @@ static RedirEntry kRedirMap[] = {
nsIAboutModule::ALLOW_SCRIPT
},
{
- "palemoon", "chrome://global/content/memoriam.xhtml",
+ "palemoon", "chrome://browser/content/palemoon.xhtml",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT
},
diff --git a/application/palemoon/config/version.txt b/application/palemoon/config/version.txt
index 87265bad0..d292f6343 100644
--- a/application/palemoon/config/version.txt
+++ b/application/palemoon/config/version.txt
@@ -1 +1 @@
-28.0.0b1 \ No newline at end of file
+28.0.0b2 \ No newline at end of file
diff --git a/application/palemoon/locales/Makefile.in b/application/palemoon/locales/Makefile.in
index 5720a76df..c81329a9a 100644
--- a/application/palemoon/locales/Makefile.in
+++ b/application/palemoon/locales/Makefile.in
@@ -124,6 +124,9 @@ libs-%:
@$(MAKE) -C ../../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
@$(MAKE) -C ../../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
@$(MAKE) -C ../../../intl/locales AB_CD=$* XPI_NAME=locale-$*
+ifdef MOZ_DEVTOOLS
+ @$(MAKE) -C ../../../devtools/client/locales AB_CD=$* XPI_NAME=locale-$*
+endif
@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
diff --git a/toolkit/locales/en-US/chrome/global/mozilla.dtd b/application/palemoon/locales/en-US/chrome/browser/palemoon.dtd
index 038d8eb75..038d8eb75 100644
--- a/toolkit/locales/en-US/chrome/global/mozilla.dtd
+++ b/application/palemoon/locales/en-US/chrome/browser/palemoon.dtd
diff --git a/application/palemoon/locales/en-US/chrome/overrides/netError.dtd b/application/palemoon/locales/en-US/chrome/overrides/netError.dtd
index c97bd1b59..04bfe9925 100644
--- a/application/palemoon/locales/en-US/chrome/overrides/netError.dtd
+++ b/application/palemoon/locales/en-US/chrome/overrides/netError.dtd
@@ -226,16 +226,6 @@ functionality specific to firefox. -->
<button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
">
-<!ENTITY errorReporting.title "Report this error">
-<!ENTITY errorReporting.longDesc "Reporting the address and certificate information for <span id='hostname'></span> will help us identify and block malicious sites. Thanks for helping create a safer web!">
-<!ENTITY errorReporting.automatic "Automatically report errors in the future">
-<!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites">
-<!ENTITY errorReporting.learnMore "Learn more…">
-<!ENTITY errorReporting.sending "Sending report">
-<!ENTITY errorReporting.sent "Report sent">
-<!ENTITY errorReporting.report "Report">
-<!ENTITY errorReporting.tryAgain "Try again">
-
<!ENTITY remoteXUL.title "Remote XUL">
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
diff --git a/application/palemoon/locales/jar.mn b/application/palemoon/locales/jar.mn
index 046cb0ac7..8d88e16fd 100644
--- a/application/palemoon/locales/jar.mn
+++ b/application/palemoon/locales/jar.mn
@@ -28,6 +28,7 @@
locale/browser/openLocation.properties (%chrome/browser/openLocation.properties)
locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd)
locale/browser/pageInfo.properties (%chrome/browser/pageInfo.properties)
+ locale/browser/palemoon.dtd (%chrome/browser/palemoon.dtd)
locale/browser/quitDialog.properties (%chrome/browser/quitDialog.properties)
locale/browser/safeMode.dtd (%chrome/browser/safeMode.dtd)
locale/browser/sanitize.dtd (%chrome/browser/sanitize.dtd)
diff --git a/application/palemoon/modules/moz.build b/application/palemoon/modules/moz.build
index 67fd22338..8032930b2 100644
--- a/application/palemoon/modules/moz.build
+++ b/application/palemoon/modules/moz.build
@@ -5,9 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-# XXX: Include this until we convert browser/ to use toolkit promises directly
-EXTRA_JS_MODULES += [ 'promise.js' ]
-
EXTRA_JS_MODULES += [
'AutoCompletePopup.jsm',
'BrowserNewTabPreloader.jsm',
diff --git a/application/palemoon/modules/promise.js b/application/palemoon/modules/promise.js
deleted file mode 100644
index 74065c8db..000000000
--- a/application/palemoon/modules/promise.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-'use strict';
-
-/*
- * Uses `Promise.jsm` as a core implementation, with additional sugar
- * from previous implementation, with inspiration from `Q` and `when`
- *
- * https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm
- * https://github.com/cujojs/when
- * https://github.com/kriskowal/q
- */
-const PROMISE_URI = 'resource://gre/modules/Promise.jsm';
-
-getEnvironment.call(this, function ({ require, exports, module, Cu }) {
-
-const Promise = Cu.import(PROMISE_URI, {}).Promise;
-const { Debugging, defer, resolve, all, reject, race } = Promise;
-
-module.metadata = {
- 'stability': 'unstable'
-};
-
-var promised = (function() {
- // Note: Define shortcuts and utility functions here in order to avoid
- // slower property accesses and unnecessary closure creations on each
- // call of this popular function.
-
- var call = Function.call;
- var concat = Array.prototype.concat;
-
- // Utility function that does following:
- // execute([ f, self, args...]) => f.apply(self, args)
- function execute (args) call.apply(call, args)
-
- // Utility function that takes promise of `a` array and maybe promise `b`
- // as arguments and returns promise for `a.concat(b)`.
- function promisedConcat(promises, unknown) {
- return promises.then(function (values) {
- return resolve(unknown)
- .then(function (value) values.concat([value]));
- });
- }
-
- return function promised(f, prototype) {
- /**
- Returns a wrapped `f`, which when called returns a promise that resolves to
- `f(...)` passing all the given arguments to it, which by the way may be
- promises. Optionally second `prototype` argument may be provided to be used
- a prototype for a returned promise.
-
- ## Example
-
- var promise = promised(Array)(1, promise(2), promise(3))
- promise.then(console.log) // => [ 1, 2, 3 ]
- **/
-
- return function promised(...args) {
- // create array of [ f, this, args... ]
- return [f, this, ...args].
- // reduce it via `promisedConcat` to get promised array of fulfillments
- reduce(promisedConcat, resolve([], prototype)).
- // finally map that to promise of `f.apply(this, args...)`
- then(execute);
- };
- };
-})();
-
-exports.promised = promised;
-exports.all = all;
-exports.defer = defer;
-exports.resolve = resolve;
-exports.reject = reject;
-exports.race = race;
-exports.Promise = Promise;
-exports.Debugging = Debugging;
-});
-
-function getEnvironment (callback) {
- let Cu, _exports, _module, _require;
-
- // CommonJS / SDK
- if (typeof(require) === 'function') {
- Cu = require('chrome').Cu;
- _exports = exports;
- _module = module;
- _require = require;
- }
- // JSM
- else if (String(this).indexOf('BackstagePass') >= 0) {
- Cu = this['Components'].utils;
- _exports = this.Promise = {};
- _module = { uri: __URI__, id: 'promise/core' };
- _require = uri => {
- let imports = {};
- Cu.import(uri, imports);
- return imports;
- };
- this.EXPORTED_SYMBOLS = ['Promise'];
- // mozIJSSubScriptLoader.loadSubscript
- } else if (~String(this).indexOf('Sandbox')) {
- Cu = this['Components'].utils;
- _exports = this;
- _module = { id: 'promise/core' };
- _require = uri => {};
- }
-
- callback({
- Cu: Cu,
- exports: _exports,
- module: _module,
- require: _require
- });
-}
-
diff --git a/application/palemoon/themes/linux/browser.css b/application/palemoon/themes/linux/browser.css
index 9a08ea4d8..7d353685d 100644
--- a/application/palemoon/themes/linux/browser.css
+++ b/application/palemoon/themes/linux/browser.css
@@ -1571,6 +1571,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
background-color: Window;
}
+.browserContainer > findbar {
+ background-color: -moz-dialog;
+ color: -moz-DialogText;
+ text-shadow: none;
+}
+
/* Throbber */
#navigator-throbber {
width: 16px;
diff --git a/application/palemoon/themes/osx/browser.css b/application/palemoon/themes/osx/browser.css
index 485ed9115..a8e86ff5c 100644
--- a/application/palemoon/themes/osx/browser.css
+++ b/application/palemoon/themes/osx/browser.css
@@ -1348,6 +1348,12 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
-moz-padding-start: 0px;
}
+.browserContainer > findbar {
+ background-color: -moz-dialog;
+ color: -moz-DialogText;
+ text-shadow: none;
+}
+
/* ::::: throbber ::::: */
#navigator-throbber {
diff --git a/application/palemoon/themes/shared/newtab/newTab.css.inc b/application/palemoon/themes/shared/newtab/newTab.css.inc
index 4ffd32d50..3341ba7e5 100644
--- a/application/palemoon/themes/shared/newtab/newTab.css.inc
+++ b/application/palemoon/themes/shared/newtab/newTab.css.inc
@@ -105,7 +105,7 @@ body {
.newtab-site:hover,
.newtab-site[dragged] {
- box-shadow: 0 3px 10px rgba(8,20,37,.6);
+ box-shadow: 0 3px 6px 1px rgba(8,20,37,.6);
}
.newtab-site[dragged] {
diff --git a/application/palemoon/themes/windows/browser.css b/application/palemoon/themes/windows/browser.css
index 099382a5a..5c044fdd4 100644
--- a/application/palemoon/themes/windows/browser.css
+++ b/application/palemoon/themes/windows/browser.css
@@ -1788,6 +1788,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
-moz-padding-start: 0px;
}
+.browserContainer > findbar {
+ background-color: -moz-dialog;
+ color: -moz-DialogText;
+ text-shadow: none;
+}
+
/* ::::: throbber ::::: */
#navigator-throbber {
@@ -3416,7 +3422,13 @@ toolbar[brighttext] #addonbar-closebutton {
border-radius: var(--toolbarbutton-border-radius);
color: black;
}
-
+
+ :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
+ :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
+ #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
+ #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme) {
+ list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
+ }
}
/* ==== Windows 8/10 (flat color) styling ==== */
@@ -3454,6 +3466,10 @@ toolbar[brighttext] #addonbar-closebutton {
border-right-style: none !important;
}
+ #main-menubar > menu:not(:-moz-lwtheme) {
+ color: inherit;
+ }
+
:-moz-any(#toolbar-menubar, #nav-bar[tabsontop=false]) :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
:-moz-any(#toolbar-menubar, #nav-bar[tabsontop=false]) :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme),
#TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
@@ -3462,13 +3478,6 @@ toolbar[brighttext] #addonbar-closebutton {
#nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme) {
list-style-image: var(--toolbarbutton-glass-image);
}
-
- :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
- :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
- #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
- #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme) {
- list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
- }
/* Show toolbar borders on vista through win8, but not on win10 and later: */
@media (-moz-os-version: windows-vista),
diff --git a/client.mk b/client.mk
index af7776e44..e8cbc625f 100644
--- a/client.mk
+++ b/client.mk
@@ -317,6 +317,7 @@ $(CONFIGURES): %: %.in $(EXTRA_CONFIG_DEPS)
CONFIG_STATUS_DEPS := \
$(wildcard $(TOPSRCDIR)/*/confvars.sh) \
+ $(wildcard $(TOPSRCDIR)/application/*/confvars.sh) \
$(CONFIGURES) \
$(TOPSRCDIR)/CLOBBER \
$(TOPSRCDIR)/nsprpub/configure \
diff --git a/devtools/client/framework/devtools-browser.js b/devtools/client/framework/devtools-browser.js
index f032f82aa..4d7176b4c 100644
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -28,7 +28,7 @@ loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main",
loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus");
loader.lazyImporter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm");
-#ifdef MC_BASILISK
+#ifdef MOZ_AUSTRALIS
loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
#endif
@@ -335,7 +335,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
* Install Developer widget
*/
installDeveloperWidget: function () {
-#ifdef MC_BASILISK
+#ifdef MOZ_AUSTRALIS
let id = "developer-button";
let widget = CustomizableUI.getWidget(id);
if (widget && widget.provider == CustomizableUI.PROVIDER_API) {
@@ -394,7 +394,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
*/
// Used by itself
installWebIDEWidget: function () {
-#ifdef MC_BASILISK
+#ifdef MOZ_AUSTRALIS
if (this.isWebIDEWidgetInstalled()) {
return;
}
@@ -422,7 +422,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
},
isWebIDEWidgetInstalled: function () {
-#ifdef MC_BASILISK
+#ifdef MOZ_AUSTRALIS
let widgetWrapper = CustomizableUI.getWidget("webide-button");
return !!(widgetWrapper && widgetWrapper.provider == CustomizableUI.PROVIDER_API);
#else
@@ -439,7 +439,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
* Uninstall WebIDE widget
*/
uninstallWebIDEWidget: function () {
-#ifdef MC_BASILISK
+#ifdef MOZ_AUSTRALIS
if (this.isWebIDEWidgetInstalled()) {
CustomizableUI.removeWidgetFromArea("webide-button");
}
@@ -454,7 +454,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
*/
// Used by webide.js
moveWebIDEWidgetInNavbar: function () {
-#ifdef MC_BASILISK
+#ifdef MOZ_AUSTRALIS
CustomizableUI.addWidgetToArea("webide-button", CustomizableUI.AREA_NAVBAR);
#else
return;
diff --git a/devtools/client/locales/en-US/animationinspector.properties b/devtools/client/locales/en-US/animationinspector.properties
index a61f07f57..57063e101 100644
--- a/devtools/client/locales/en-US/animationinspector.properties
+++ b/devtools/client/locales/en-US/animationinspector.properties
@@ -121,12 +121,12 @@ player.somePropertiesOnCompositorTooltip=Some animation properties are optimized
# run.
timeline.rateSelectorTooltip=Set the animations playback rates
-# LOCALIZATION NOTE (timeline.pauseResumeButtonTooltip):
+# LOCALIZATION NOTE (timeline.pausedButtonTooltip):
# This string is displayed in the timeline toolbar, as the tooltip of the
# pause/resume button that can be used to pause or resume the animations
timeline.pausedButtonTooltip=Resume the animations
-# LOCALIZATION NOTE (timeline.pauseResumeButtonTooltip):
+# LOCALIZATION NOTE (timeline.resumedButtonTooltip):
# This string is displayed in the timeline toolbar, as the tooltip of the
# pause/resume button that can be used to pause or resume the animations
timeline.resumedButtonTooltip=Pause the animations
diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp
index 169c3fe7a..e39abf1a6 100644
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -47,6 +47,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries)
+ tmp->Disconnect();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver)
@@ -184,9 +185,10 @@ DOMIntersectionObserver::Connect()
if (mConnected) {
return;
}
+ mConnected = true;
+
nsIDocument* document = mOwner->GetExtantDoc();
document->AddIntersectionObserver(this);
- mConnected = true;
}
void
@@ -202,7 +204,9 @@ DOMIntersectionObserver::Disconnect()
mObservationTargets.Clear();
if (mOwner) {
nsIDocument* document = mOwner->GetExtantDoc();
- document->RemoveIntersectionObserver(this);
+ if (document) {
+ document->RemoveIntersectionObserver(this);
+ }
}
mConnected = false;
}
@@ -248,6 +252,12 @@ EdgeInclusiveIntersection(const nsRect& aRect, const nsRect& aOtherRect)
return Some(nsRect(left, top, right - left, bottom - top));
}
+enum class BrowsingContextInfo {
+ SimilarOriginBrowsingContext,
+ DifferentOriginBrowsingContext,
+ UnknownBrowsingContext
+};
+
void
DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time)
{
@@ -359,11 +369,22 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
}
}
- nsRect rootIntersectionRect = rootRect;
- bool isInSimilarOriginBrowsingContext = rootFrame && targetFrame &&
- CheckSimilarOrigin(root, target);
+ nsRect rootIntersectionRect;
+ BrowsingContextInfo isInSimilarOriginBrowsingContext =
+ BrowsingContextInfo::UnknownBrowsingContext;
+
+ if (rootFrame && targetFrame) {
+ rootIntersectionRect = rootRect;
+ }
+
+ if (root && target) {
+ isInSimilarOriginBrowsingContext = CheckSimilarOrigin(root, target) ?
+ BrowsingContextInfo::SimilarOriginBrowsingContext :
+ BrowsingContextInfo::DifferentOriginBrowsingContext;
+ }
- if (isInSimilarOriginBrowsingContext) {
+ if (isInSimilarOriginBrowsingContext ==
+ BrowsingContextInfo::SimilarOriginBrowsingContext) {
rootIntersectionRect.Inflate(rootMargin);
}
@@ -413,7 +434,9 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
if (target->UpdateIntersectionObservation(this, threshold)) {
QueueIntersectionObserverEntry(
target, time,
- isInSimilarOriginBrowsingContext ? Some(rootIntersectionRect) : Nothing(),
+ isInSimilarOriginBrowsingContext ==
+ BrowsingContextInfo::DifferentOriginBrowsingContext ?
+ Nothing() : Some(rootIntersectionRect),
targetRect, intersectionRect, intersectionRatio
);
}
diff --git a/dom/base/DOMIntersectionObserver.h b/dom/base/DOMIntersectionObserver.h
index 3eb10ad38..8144fc5c5 100644
--- a/dom/base/DOMIntersectionObserver.h
+++ b/dom/base/DOMIntersectionObserver.h
@@ -101,9 +101,7 @@ protected:
class DOMIntersectionObserver final : public nsISupports,
public nsWrapperCache
{
- virtual ~DOMIntersectionObserver() {
- Disconnect();
- }
+ virtual ~DOMIntersectionObserver() { }
public:
DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index 092755590..52d06b0f8 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3912,44 +3912,55 @@ Element::ClearDataset()
slots->mDataset = nullptr;
}
-nsTArray<Element::nsDOMSlots::IntersectionObserverRegistration>*
+nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>*
Element::RegisteredIntersectionObservers()
{
nsDOMSlots* slots = DOMSlots();
return &slots->mRegisteredIntersectionObservers;
}
+enum nsPreviousIntersectionThreshold {
+ eUninitialized = -2,
+ eNonIntersecting = -1
+};
+
void
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
- RegisteredIntersectionObservers()->AppendElement(
- nsDOMSlots::IntersectionObserverRegistration { aObserver, -1 });
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
+ RegisteredIntersectionObservers();
+ if (observers->Contains(aObserver)) {
+ return;
+ }
+
+ // Value can be:
+ // -2: Makes sure next calculated threshold always differs, leading to a
+ // notification task being scheduled.
+ // -1: Non-intersecting.
+ // >= 0: Intersecting, valid index of aObserver->mThresholds.
+ RegisteredIntersectionObservers()->Put(aObserver, eUninitialized);
}
void
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
{
- nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
- for (uint32_t i = 0; i < observers->Length(); ++i) {
- nsDOMSlots::IntersectionObserverRegistration reg = observers->ElementAt(i);
- if (reg.observer == aObserver) {
- observers->RemoveElementAt(i);
- break;
- }
- }
+ observers->Remove(aObserver);
}
bool
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
{
- nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
RegisteredIntersectionObservers();
- for (auto& reg : *observers) {
- if (reg.observer == aObserver && reg.previousThreshold != aThreshold) {
- reg.previousThreshold = aThreshold;
- return true;
- }
+ if (!observers->Contains(aObserver)) {
+ return false;
+ }
+ int32_t previousThreshold = observers->Get(aObserver);
+ if (previousThreshold != aThreshold) {
+ observers->Put(aObserver, aThreshold);
+ return true;
}
return false;
}
diff --git a/dom/base/Element.h b/dom/base/Element.h
index cf1d197e2..049984d1b 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1380,7 +1380,7 @@ protected:
nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
- nsTArray<nsDOMSlots::IntersectionObserverRegistration>* RegisteredIntersectionObservers();
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* RegisteredIntersectionObservers();
private:
/**
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index b22a0d4ff..fde983e7c 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -608,6 +608,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
mLabelsList = nullptr;
mCustomElementData = nullptr;
mClassList = nullptr;
+ mRegisteredIntersectionObservers.Clear();
}
size_t
@@ -1359,6 +1360,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
{
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
if (slots) {
+ if (tmp->IsElement()) {
+ Element* elem = tmp->AsElement();
+ for (auto iter = slots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
+ DOMIntersectionObserver* observer = iter.Key();
+ observer->UnlinkTarget(*elem);
+ }
+ }
slots->Unlink(tmp->IsXULElement());
}
}
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 1cd8033bb..7c74e9cd4 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -21,6 +21,7 @@
#include "nsIWeakReference.h" // base class
#include "nsNodeUtils.h" // class member nsNodeUtils::CloneNodeImpl
#include "nsIHTMLCollection.h"
+#include "nsDataHashtable.h"
class ContentUnbinder;
class nsContentList;
@@ -353,12 +354,7 @@ public:
/**
* Registered Intersection Observers on the element.
*/
- struct IntersectionObserverRegistration {
- DOMIntersectionObserver* observer;
- int32_t previousThreshold;
- };
-
- nsTArray<IntersectionObserverRegistration> mRegisteredIntersectionObservers;
+ nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t> mRegisteredIntersectionObservers;
};
protected:
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index fd3b52948..8acfd901a 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12507,7 +12507,8 @@ nsDocument::ScheduleIntersectionObserverNotification()
void
nsDocument::NotifyIntersectionObservers()
{
- for (const auto& observer : mIntersectionObservers) {
+ nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers);
+ for (const auto& observer : observers) {
observer->Notify();
}
}
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 4e384c4d2..884ad69ca 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -14633,7 +14633,9 @@ nsGlobalWindow::NotifyDefaultButtonLoaded(Element& aDefaultButton,
return;
}
LayoutDeviceIntRect buttonRect =
- LayoutDeviceIntRect::FromUnknownRect(frame->GetScreenRect());
+ LayoutDeviceIntRect::FromAppUnitsToNearest(
+ frame->GetScreenRectInAppUnits(),
+ frame->PresContext()->AppUnitsPerDevPixel());
// Get the widget rect in screen coordinates.
nsIWidget *widget = GetNearestWidget();
diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp
index 69a9414fe..ecea95dc1 100644
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -297,15 +297,6 @@ nsNodeUtils::LastRelease(nsINode* aNode)
NodeWillBeDestroyed, (aNode));
}
- if (aNode->IsElement()) {
- Element* elem = aNode->AsElement();
- FragmentOrElement::nsDOMSlots* domSlots =
- static_cast<FragmentOrElement::nsDOMSlots*>(slots);
- for (auto& reg : domSlots->mRegisteredIntersectionObservers) {
- reg.observer->UnlinkTarget(*elem);
- }
- }
-
delete slots;
aNode->mSlots = nullptr;
}
diff --git a/dom/base/test/test_intersectionobservers.html b/dom/base/test/test_intersectionobservers.html
index e7875e3af..10e3d7712 100644
--- a/dom/base/test/test_intersectionobservers.html
+++ b/dom/base/test/test_intersectionobservers.html
@@ -325,7 +325,7 @@ limitations under the License.
});
- it('does not trigger if target does not intersect when observing begins',
+ it('does trigger if target does not intersect when observing begins',
function(done) {
var spy = sinon.spy();
@@ -334,7 +334,7 @@ limitations under the License.
targetEl2.style.top = '-40px';
io.observe(targetEl2);
callDelayed(function() {
- expect(spy.callCount).to.be(0);
+ expect(spy.callCount).to.be(1);
done();
}, ASYNC_TIMEOUT);
});
@@ -528,7 +528,7 @@ limitations under the License.
spy.waitForNotification(function() {
expect(spy.callCount).to.be(1);
var records = sortRecords(spy.lastCall.args[0]);
- expect(records.length).to.be(2);
+ expect(records.length).to.be(3);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.25);
expect(records[1].target).to.be(targetEl2);
@@ -636,10 +636,10 @@ limitations under the License.
expect(records.length).to.be(3);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.5);
- expect(records[1].target).to.be(targetEl3);
- expect(records[1].intersectionRatio).to.be(0.5);
- expect(records[2].target).to.be(targetEl4);
+ expect(records[2].target).to.be(targetEl3);
expect(records[2].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.5);
io.disconnect();
done();
}, {root: rootEl, rootMargin: '-10px 10%'});
@@ -652,11 +652,11 @@ limitations under the License.
function(done) {
io = new IntersectionObserver(function(records) {
records = sortRecords(records);
- expect(records.length).to.be(2);
+ expect(records.length).to.be(4);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.5);
- expect(records[1].target).to.be(targetEl4);
- expect(records[1].intersectionRatio).to.be(0.5);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.5);
io.disconnect();
done();
}, {root: rootEl, rootMargin: '-5% -2.5% 0px'});
@@ -669,13 +669,13 @@ limitations under the License.
function(done) {
io = new IntersectionObserver(function(records) {
records = sortRecords(records);
- expect(records.length).to.be(3);
+ expect(records.length).to.be(4);
expect(records[0].target).to.be(targetEl1);
expect(records[0].intersectionRatio).to.be(0.5);
expect(records[1].target).to.be(targetEl2);
expect(records[1].intersectionRatio).to.be(0.5);
- expect(records[2].target).to.be(targetEl4);
- expect(records[2].intersectionRatio).to.be(0.25);
+ expect(records[3].target).to.be(targetEl4);
+ expect(records[3].intersectionRatio).to.be(0.25);
io.disconnect();
done();
}, {root: rootEl, rootMargin: '5% -2.5% -10px -190px'});
@@ -705,9 +705,9 @@ limitations under the License.
spy.waitForNotification(function() {
expect(spy.callCount).to.be(1);
var records = sortRecords(spy.lastCall.args[0]);
- expect(records.length).to.be(1);
- expect(records[0].intersectionRatio).to.be(0);
- expect(records[0].target).to.be(targetEl2);
+ expect(records.length).to.be(2);
+ expect(records[1].intersectionRatio).to.be(0);
+ expect(records[1].target).to.be(targetEl2);
done();
}, ASYNC_TIMEOUT);
},
@@ -797,14 +797,14 @@ limitations under the License.
function(done) {
document.getElementById('fixtures').appendChild(rootEl);
callDelayed(function() {
- expect(spy.callCount).to.be(0);
+ expect(spy.callCount).to.be(1);
done();
}, ASYNC_TIMEOUT);
},
function(done) {
parentEl.insertBefore(targetEl1, targetEl2);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(1);
+ expect(spy.callCount).to.be(2);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(1);
@@ -815,7 +815,7 @@ limitations under the License.
function(done) {
grandParentEl.parentNode.removeChild(grandParentEl);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(2);
+ expect(spy.callCount).to.be(3);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(0);
@@ -826,7 +826,7 @@ limitations under the License.
function(done) {
rootEl.appendChild(targetEl1);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(3);
+ expect(spy.callCount).to.be(4);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(1);
@@ -837,7 +837,7 @@ limitations under the License.
function(done) {
rootEl.parentNode.removeChild(rootEl);
spy.waitForNotification(function() {
- expect(spy.callCount).to.be(4);
+ expect(spy.callCount).to.be(5);
var records = sortRecords(spy.lastCall.args[0]);
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(0);
@@ -867,8 +867,14 @@ limitations under the License.
targetEl1.style.top = '220px';
targetEl1.style.left = '220px';
+
+ var callCount = 0;
io = new IntersectionObserver(function(records) {
+ callCount++;
+ if (callCount <= 1) {
+ return;
+ }
expect(records.length).to.be(1);
expect(records[0].intersectionRatio).to.be(1);
done();
@@ -891,6 +897,19 @@ limitations under the License.
var win = window.open("intersectionobserver_window.html");
});
+ it('triggers only once if observed multiple times (and does not crash when collected)', function(done) {
+ var spy = sinon.spy();
+ io = new IntersectionObserver(spy, {root: rootEl});
+ io.observe(targetEl1);
+ io.observe(targetEl1);
+ io.observe(targetEl1);
+
+ callDelayed(function () {
+ expect(spy.callCount).to.be(1);
+ done();
+ }, ASYNC_TIMEOUT);
+ });
+
});
describe('observe subframe', function () {
diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp
index 4b9776c0a..f33bfa5a8 100755
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -280,16 +280,10 @@ Event::GetType(nsAString& aType)
return NS_OK;
}
-static EventTarget*
-GetDOMEventTarget(nsIDOMEventTarget* aTarget)
-{
- return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
-}
-
EventTarget*
Event::GetTarget() const
{
- return GetDOMEventTarget(mEvent->mTarget);
+ return mEvent->GetDOMEventTarget();
}
NS_IMETHODIMP
@@ -302,7 +296,7 @@ Event::GetTarget(nsIDOMEventTarget** aTarget)
EventTarget*
Event::GetCurrentTarget() const
{
- return GetDOMEventTarget(mEvent->mCurrentTarget);
+ return mEvent->GetCurrentDOMEventTarget();
}
NS_IMETHODIMP
@@ -349,11 +343,7 @@ Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
EventTarget*
Event::GetOriginalTarget() const
{
- if (mEvent->mOriginalTarget) {
- return GetDOMEventTarget(mEvent->mOriginalTarget);
- }
-
- return GetTarget();
+ return mEvent->GetOriginalDOMEventTarget();
}
NS_IMETHODIMP
diff --git a/editor/libeditor/EditorBase.cpp b/editor/libeditor/EditorBase.cpp
index 0c4a2a41d..f7988cd1a 100644
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -5092,19 +5092,16 @@ EditorBase::IsActiveInDOMWindow()
}
bool
-EditorBase::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
+EditorBase::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
{
// If the event is trusted, the event should always cause input.
- NS_ENSURE_TRUE(aEvent, false);
-
- WidgetEvent* widgetEvent = aEvent->WidgetEventPtr();
- if (NS_WARN_IF(!widgetEvent)) {
+ if (NS_WARN_IF(!aGUIEvent)) {
return false;
}
// If this is dispatched by using cordinates but this editor doesn't have
// focus, we shouldn't handle it.
- if (widgetEvent->IsUsingCoordinates()) {
+ if (aGUIEvent->IsUsingCoordinates()) {
nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
if (!focusedContent) {
return false;
@@ -5117,8 +5114,7 @@ EditorBase::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
// Note that if we allow to handle such events, editor may be confused by
// strange event order.
bool needsWidget = false;
- WidgetGUIEvent* widgetGUIEvent = nullptr;
- switch (widgetEvent->mMessage) {
+ switch (aGUIEvent->mMessage) {
case eUnidentifiedEvent:
// If events are not created with proper event interface, their message
// are initialized with eUnidentifiedEvent. Let's ignore such event.
@@ -5130,25 +5126,26 @@ EditorBase::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
case eCompositionCommitAsIs:
// Don't allow composition events whose internal event are not
// WidgetCompositionEvent.
- widgetGUIEvent = aEvent->WidgetEventPtr()->AsCompositionEvent();
+ if (!aGUIEvent->AsCompositionEvent()) {
+ return false;
+ }
needsWidget = true;
break;
default:
break;
}
- if (needsWidget &&
- (!widgetGUIEvent || !widgetGUIEvent->mWidget)) {
+ if (needsWidget && !aGUIEvent->mWidget) {
return false;
}
// Accept all trusted events.
- if (widgetEvent->IsTrusted()) {
+ if (aGUIEvent->IsTrusted()) {
return true;
}
// Ignore untrusted mouse event.
// XXX Why are we handling other untrusted input events?
- if (widgetEvent->AsMouseEventBase()) {
+ if (aGUIEvent->AsMouseEventBase()) {
return false;
}
diff --git a/editor/libeditor/EditorBase.h b/editor/libeditor/EditorBase.h
index dd4b9695e..dbd00771e 100644
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -247,7 +247,8 @@ public:
* IME event handlers.
*/
virtual nsresult BeginIMEComposition(WidgetCompositionEvent* aEvent);
- virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0;
+ virtual nsresult UpdateIMEComposition(
+ WidgetCompositionEvent* aCompositionChangeEvent) = 0;
void EndIMEComposition();
void SwitchTextDirectionTo(uint32_t aDirection);
@@ -870,12 +871,12 @@ public:
virtual bool IsActiveInDOMWindow();
/**
- * Whether the aEvent should be handled by this editor or not. When this
- * returns FALSE, The aEvent shouldn't be handled on this editor,
- * i.e., The aEvent should be handled by another inner editor or ancestor
+ * Whether the aGUIEvent should be handled by this editor or not. When this
+ * returns false, The aGUIEvent shouldn't be handled on this editor,
+ * i.e., The aGUIEvent should be handled by another inner editor or ancestor
* elements.
*/
- virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
+ virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent);
/**
* FindSelectionRoot() returns a selection root of this editor when aNode
diff --git a/editor/libeditor/EditorEventListener.cpp b/editor/libeditor/EditorEventListener.cpp
index f90458d3e..a6fcfd933 100644
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -214,7 +214,7 @@ EditorEventListener::InstallToEditor()
void
EditorEventListener::Disconnect()
{
- if (!mEditorBase) {
+ if (DetachedFromEditor()) {
return;
}
UninstallFromEditor();
@@ -301,8 +301,7 @@ EditorEventListener::UninstallFromEditor()
already_AddRefed<nsIPresShell>
EditorEventListener::GetPresShell()
{
- NS_PRECONDITION(mEditorBase,
- "The caller must check whether this is connected to an editor");
+ MOZ_ASSERT(!DetachedFromEditor());
return mEditorBase->GetPresShell();
}
@@ -316,8 +315,7 @@ EditorEventListener::GetPresContext()
nsIContent*
EditorEventListener::GetFocusedRootContent()
{
- NS_ENSURE_TRUE(mEditorBase, nullptr);
-
+ MOZ_ASSERT(!DetachedFromEditor());
nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContent();
if (!focusedContent) {
return nullptr;
@@ -336,8 +334,7 @@ EditorEventListener::GetFocusedRootContent()
bool
EditorEventListener::EditorHasFocus()
{
- NS_PRECONDITION(mEditorBase,
- "The caller must check whether this is connected to an editor");
+ MOZ_ASSERT(!DetachedFromEditor());
nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContent();
if (!focusedContent) {
return false;
@@ -348,16 +345,23 @@ EditorEventListener::EditorHasFocus()
NS_IMPL_ISUPPORTS(EditorEventListener, nsIDOMEventListener)
-NS_IMETHODIMP
-EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
+bool
+EditorEventListener::DetachedFromEditor() const
{
- NS_ENSURE_TRUE(mEditorBase, NS_ERROR_FAILURE);
-
- nsCOMPtr<nsIEditor> kungFuDeathGrip = mEditorBase;
- Unused << kungFuDeathGrip; // mEditorBase is not referred to in this function
+ return !mEditorBase;
+}
- WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
+bool
+EditorEventListener::DetachedFromEditorOrDefaultPrevented(
+ WidgetEvent* aWidgetEvent) const
+{
+ return NS_WARN_IF(!aWidgetEvent) || DetachedFromEditor() ||
+ aWidgetEvent->DefaultPrevented();
+}
+NS_IMETHODIMP
+EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
+{
// Let's handle each event with the message of the internal event of the
// coming event. If the DOM event was created with improper interface,
// e.g., keydown event is created with |new MouseEvent("keydown", {});|,
@@ -368,6 +372,7 @@ EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
// calling it, this queries the specific interface. If it would fail,
// each event handler would just ignore the event. So, in this method,
// you don't need to check if the QI succeeded before each call.
+ WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
switch (internalEvent->mMessage) {
// dragenter
case eDragEnter: {
@@ -454,19 +459,19 @@ EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
}
// focus
case eFocus:
- return Focus(aEvent);
+ return Focus(internalEvent);
// blur
case eBlur:
- return Blur(aEvent);
+ return Blur(internalEvent);
// text
case eCompositionChange:
- return HandleText(aEvent);
+ return HandleChangeComposition(internalEvent->AsCompositionEvent());
// compositionstart
case eCompositionStart:
- return HandleStartComposition(aEvent);
+ return HandleStartComposition(internalEvent->AsCompositionEvent());
// compositionend
case eCompositionEnd:
- HandleEndComposition(aEvent);
+ HandleEndComposition(internalEvent->AsCompositionEvent());
return NS_OK;
default:
break;
@@ -477,10 +482,10 @@ EditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
// We should accept "focus" and "blur" event even if it's synthesized with
// wrong interface for compatibility with older Gecko.
if (eventType.EqualsLiteral("focus")) {
- return Focus(aEvent);
+ return Focus(internalEvent);
}
if (eventType.EqualsLiteral("blur")) {
- return Blur(aEvent);
+ return Blur(internalEvent);
}
#ifdef DEBUG
nsPrintfCString assertMessage("Editor doesn't handle \"%s\" event "
@@ -541,18 +546,22 @@ bool IsCtrlShiftPressed(nsIDOMKeyEvent* aEvent, bool& isRTL)
nsresult
EditorEventListener::KeyUp(nsIDOMKeyEvent* aKeyEvent)
{
- NS_ENSURE_TRUE(aKeyEvent, NS_OK);
+ if (NS_WARN_IF(!aKeyEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
if (!mHaveBidiKeyboards) {
return NS_OK;
}
+ // XXX Why doesn't this method check if it's consumed?
+ RefPtr<EditorBase> editorBase(mEditorBase);
uint32_t keyCode = 0;
aKeyEvent->GetKeyCode(&keyCode);
if ((keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT ||
keyCode == nsIDOMKeyEvent::DOM_VK_CONTROL) &&
- mShouldSwitchTextDirection && mEditorBase->IsPlaintextEditor()) {
- mEditorBase->SwitchTextDirectionTo(mSwitchToRTL ?
+ mShouldSwitchTextDirection && editorBase->IsPlaintextEditor()) {
+ editorBase->SwitchTextDirectionTo(mSwitchToRTL ?
nsIPlaintextEditor::eEditorRightToLeft :
nsIPlaintextEditor::eEditorLeftToRight);
mShouldSwitchTextDirection = false;
@@ -563,12 +572,15 @@ EditorEventListener::KeyUp(nsIDOMKeyEvent* aKeyEvent)
nsresult
EditorEventListener::KeyDown(nsIDOMKeyEvent* aKeyEvent)
{
- NS_ENSURE_TRUE(aKeyEvent, NS_OK);
+ if (NS_WARN_IF(!aKeyEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
if (!mHaveBidiKeyboards) {
return NS_OK;
}
+ // XXX Why isn't this method check if it's consumed?
uint32_t keyCode = 0;
aKeyEvent->GetKeyCode(&keyCode);
if (keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT) {
@@ -588,29 +600,23 @@ EditorEventListener::KeyDown(nsIDOMKeyEvent* aKeyEvent)
nsresult
EditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
{
- NS_ENSURE_TRUE(aKeyEvent, NS_OK);
-
- if (!mEditorBase->IsAcceptableInputEvent(aKeyEvent->AsEvent())) {
+ if (NS_WARN_IF(!aKeyEvent)) {
return NS_OK;
}
- // DOM event handling happens in two passes, the client pass and the system
- // pass. We do all of our processing in the system pass, to allow client
- // handlers the opportunity to cancel events and prevent typing in the editor.
- // If the client pass cancelled the event, defaultPrevented will be true
- // below.
-
- bool defaultPrevented;
- aKeyEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ WidgetKeyboardEvent* keypressEvent =
+ aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
+ MOZ_ASSERT(keypressEvent,
+ "DOM key event's internal event must be WidgetKeyboardEvent");
+ if (!editorBase->IsAcceptableInputEvent(keypressEvent) ||
+ DetachedFromEditorOrDefaultPrevented(keypressEvent)) {
return NS_OK;
}
- nsresult rv = mEditorBase->HandleKeyPressEvent(aKeyEvent);
+ nsresult rv = editorBase->HandleKeyPressEvent(aKeyEvent);
NS_ENSURE_SUCCESS(rv, rv);
-
- aKeyEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (DetachedFromEditorOrDefaultPrevented(keypressEvent)) {
return NS_OK;
}
@@ -619,11 +625,7 @@ EditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
}
// Now, ask the native key bindings to handle the event.
- WidgetKeyboardEvent* keyEvent =
- aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
- MOZ_ASSERT(keyEvent,
- "DOM key event's internal event must be WidgetKeyboardEvent");
- nsIWidget* widget = keyEvent->mWidget;
+ nsIWidget* widget = keypressEvent->mWidget;
// If the event is created by chrome script, the widget is always nullptr.
if (!widget) {
nsCOMPtr<nsIPresShell> ps = GetPresShell();
@@ -632,10 +634,10 @@ EditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
NS_ENSURE_TRUE(widget, NS_OK);
}
- nsCOMPtr<nsIDocument> doc = mEditorBase->GetDocument();
+ nsCOMPtr<nsIDocument> doc = editorBase->GetDocument();
bool handled = widget->ExecuteNativeKeyBinding(
nsIWidget::NativeKeyBindingsForRichTextEditor,
- *keyEvent, DoCommandCallback, doc);
+ *keypressEvent, DoCommandCallback, doc);
if (handled) {
aKeyEvent->AsEvent()->PreventDefault();
}
@@ -645,9 +647,15 @@ EditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
nsresult
EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
{
+ if (NS_WARN_IF(!aMouseEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
// nothing to do if editor isn't editable or clicked on out of the editor.
- if (mEditorBase->IsReadonly() || mEditorBase->IsDisabled() ||
- !mEditorBase->IsAcceptableInputEvent(aMouseEvent->AsEvent())) {
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ WidgetMouseEvent* clickEvent =
+ aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
+ if (editorBase->IsReadonly() || editorBase->IsDisabled() ||
+ !editorBase->IsAcceptableInputEvent(clickEvent)) {
return NS_OK;
}
@@ -658,26 +666,23 @@ EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
if (presContext) {
IMEStateManager::OnClickInEditor(presContext, GetFocusedRootContent(),
aMouseEvent);
- }
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
+ }
}
- bool preventDefault;
- nsresult rv = aMouseEvent->AsEvent()->GetDefaultPrevented(&preventDefault);
- if (NS_FAILED(rv) || preventDefault) {
+ if (DetachedFromEditorOrDefaultPrevented(clickEvent)) {
// We're done if 'preventdefault' is true (see for example bug 70698).
- return rv;
- }
-
- // IMEStateManager::OnClickInEditor() may cause anything because it may
- // set input context. For example, it may cause opening VKB, changing focus
- // or reflow. So, mEditorBase here might have been gone.
- if (!mEditorBase) {
return NS_OK;
}
// If we got a mouse down inside the editing area, we should force the
// IME to commit before we change the cursor position
- mEditorBase->ForceCompositionEnd();
+ editorBase->ForceCompositionEnd();
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
int16_t button = -1;
aMouseEvent->GetButton(&button);
@@ -690,6 +695,10 @@ EditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
nsresult
EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
{
+ MOZ_ASSERT(aMouseEvent);
+ MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(
+ aMouseEvent->AsEvent()->WidgetEventPtr()));
+
if (!Preferences::GetBool("middlemouse.paste", false)) {
// Middle click paste isn't enabled.
return NS_OK;
@@ -705,7 +714,8 @@ EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
return NS_ERROR_NULL_POINTER;
}
- RefPtr<Selection> selection = mEditorBase->GetSelection();
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ RefPtr<Selection> selection = editorBase->GetSelection();
if (selection) {
selection->Collapse(parent, offset);
}
@@ -717,7 +727,7 @@ EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
nsCOMPtr<nsIEditorMailSupport> mailEditor;
if (ctrlKey) {
- mailEditor = do_QueryObject(mEditorBase);
+ mailEditor = do_QueryObject(editorBase);
}
nsresult rv;
@@ -735,7 +745,7 @@ EditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
if (mailEditor) {
mailEditor->PasteAsQuotation(clipboard);
} else {
- mEditorBase->Paste(clipboard);
+ editorBase->Paste(clipboard);
}
// Prevent the event from propagating up to be possibly handled
@@ -751,16 +761,12 @@ bool
EditorEventListener::NotifyIMEOfMouseButtonEvent(
nsIDOMMouseEvent* aMouseEvent)
{
+ MOZ_ASSERT(aMouseEvent);
+
if (!EditorHasFocus()) {
return false;
}
- bool defaultPrevented;
- nsresult rv = aMouseEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- NS_ENSURE_SUCCESS(rv, false);
- if (defaultPrevented) {
- return false;
- }
nsPresContext* presContext = GetPresContext();
NS_ENSURE_TRUE(presContext, false);
return IMEStateManager::OnMouseButtonEventInEditor(presContext,
@@ -771,27 +777,36 @@ EditorEventListener::NotifyIMEOfMouseButtonEvent(
nsresult
EditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
+ // FYI: We don't need to check if it's already consumed here because
+ // we need to commit composition at mouse button operation.
// FYI: This may be called by HTMLEditorEventListener::MouseDown() even
// when the event is not acceptable for committing composition.
- if (mEditorBase) {
- mEditorBase->ForceCompositionEnd();
+ if (DetachedFromEditor()) {
+ return NS_OK;
}
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ editorBase->ForceCompositionEnd();
return NS_OK;
}
nsresult
-EditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
+EditorEventListener::HandleChangeComposition(
+ WidgetCompositionEvent* aCompositionChangeEvent)
{
- if (!mEditorBase->IsAcceptableInputEvent(aTextEvent)) {
+ MOZ_ASSERT(!aCompositionChangeEvent->DefaultPrevented(),
+ "eCompositionChange event shouldn't be cancelable");
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ if (DetachedFromEditor() ||
+ !editorBase->IsAcceptableInputEvent(aCompositionChangeEvent)) {
return NS_OK;
}
// if we are readonly or disabled, then do nothing.
- if (mEditorBase->IsReadonly() || mEditorBase->IsDisabled()) {
+ if (editorBase->IsReadonly() || editorBase->IsDisabled()) {
return NS_OK;
}
- return mEditorBase->UpdateIMEComposition(aTextEvent);
+ return editorBase->UpdateIMEComposition(aCompositionChangeEvent);
}
/**
@@ -801,7 +816,9 @@ EditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
nsresult
EditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
+ if (NS_WARN_IF(!aDragEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE(presShell, NS_OK);
@@ -824,15 +841,13 @@ EditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
nsresult
EditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
-
- nsCOMPtr<nsIDOMNode> parent;
- bool defaultPrevented;
- aDragEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (NS_WARN_IF(!aDragEvent) ||
+ DetachedFromEditorOrDefaultPrevented(
+ aDragEvent->AsEvent()->WidgetEventPtr())) {
return NS_OK;
}
+ nsCOMPtr<nsIDOMNode> parent;
aDragEvent->GetRangeParent(getter_AddRefs(parent));
nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
@@ -887,7 +902,15 @@ EditorEventListener::CleanupDragDropCaret()
nsresult
EditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
+ // XXX If aDragEvent was created by chrome script, its defaultPrevented
+ // may be true, though. We shouldn't handle such event but we don't
+ // have a way to distinguish if coming event is created by chrome script.
+ NS_WARNING_ASSERTION(
+ !aDragEvent->AsEvent()->WidgetEventPtr()->DefaultPrevented(),
+ "eDragExit shouldn't be cancelable");
+ if (NS_WARN_IF(!aDragEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
CleanupDragDropCaret();
@@ -897,13 +920,11 @@ EditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
nsresult
EditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
{
- NS_ENSURE_TRUE(aDragEvent, NS_OK);
-
CleanupDragDropCaret();
- bool defaultPrevented;
- aDragEvent->AsEvent()->GetDefaultPrevented(&defaultPrevented);
- if (defaultPrevented) {
+ if (NS_WARN_IF(!aDragEvent) ||
+ DetachedFromEditorOrDefaultPrevented(
+ aDragEvent->AsEvent()->WidgetEventPtr())) {
return NS_OK;
}
@@ -914,7 +935,8 @@ EditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
if (!dropParent->IsEditable() || !CanDrop(aDragEvent)) {
// was it because we're read-only?
- if ((mEditorBase->IsReadonly() || mEditorBase->IsDisabled()) &&
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ if ((editorBase->IsReadonly() || editorBase->IsDisabled()) &&
!IsFileControlTextBox()) {
// it was decided to "eat" the event as this is the "least surprise"
// since someone else handling it might be unintentional and the
@@ -927,14 +949,19 @@ EditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
aDragEvent->AsEvent()->StopPropagation();
aDragEvent->AsEvent()->PreventDefault();
- return mEditorBase->InsertFromDrop(aDragEvent->AsEvent());
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ return editorBase->InsertFromDrop(aDragEvent->AsEvent());
}
bool
EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
{
+ MOZ_ASSERT(!DetachedFromEditorOrDefaultPrevented(
+ aEvent->AsEvent()->WidgetEventPtr()));
+
// if the target doc is read-only, we can't drop
- if (mEditorBase->IsReadonly() || mEditorBase->IsDisabled()) {
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ if (editorBase->IsReadonly() || editorBase->IsDisabled()) {
return false;
}
@@ -950,7 +977,7 @@ EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
// can be dropped as well.
if (!types.Contains(NS_LITERAL_STRING(kTextMime)) &&
!types.Contains(NS_LITERAL_STRING(kMozTextInternal)) &&
- (mEditorBase->IsPlaintextEditor() ||
+ (editorBase->IsPlaintextEditor() ||
(!types.Contains(NS_LITERAL_STRING(kHTMLMime)) &&
!types.Contains(NS_LITERAL_STRING(kFileMime))))) {
return false;
@@ -968,7 +995,7 @@ EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
// There is a source node, so compare the source documents and this document.
// Disallow drops on the same document.
- nsCOMPtr<nsIDOMDocument> domdoc = mEditorBase->GetDOMDocument();
+ nsCOMPtr<nsIDOMDocument> domdoc = editorBase->GetDOMDocument();
NS_ENSURE_TRUE(domdoc, false);
nsCOMPtr<nsIDOMDocument> sourceDoc;
@@ -988,7 +1015,7 @@ EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
return true;
}
- RefPtr<Selection> selection = mEditorBase->GetSelection();
+ RefPtr<Selection> selection = editorBase->GetSelection();
if (!selection) {
return false;
}
@@ -1030,46 +1057,63 @@ EditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
}
nsresult
-EditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
+EditorEventListener::HandleStartComposition(
+ WidgetCompositionEvent* aCompositionStartEvent)
{
- if (!mEditorBase->IsAcceptableInputEvent(aCompositionEvent)) {
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ if (DetachedFromEditor() ||
+ !editorBase->IsAcceptableInputEvent(aCompositionStartEvent)) {
return NS_OK;
}
- WidgetCompositionEvent* compositionStart =
- aCompositionEvent->WidgetEventPtr()->AsCompositionEvent();
- return mEditorBase->BeginIMEComposition(compositionStart);
+ // Although, "compositionstart" should be cancelable, but currently,
+ // eCompositionStart event coming from widget is not cancelable.
+ MOZ_ASSERT(!aCompositionStartEvent->DefaultPrevented(),
+ "eCompositionStart shouldn't be cancelable");
+ return editorBase->BeginIMEComposition(aCompositionStartEvent);
}
void
-EditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
+EditorEventListener::HandleEndComposition(
+ WidgetCompositionEvent* aCompositionEndEvent)
{
- if (!mEditorBase->IsAcceptableInputEvent(aCompositionEvent)) {
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ if (DetachedFromEditor() ||
+ !editorBase->IsAcceptableInputEvent(aCompositionEndEvent)) {
return;
}
-
- mEditorBase->EndIMEComposition();
+ MOZ_ASSERT(!aCompositionEndEvent->DefaultPrevented(),
+ "eCompositionEnd shouldn't be cancelable");
+ editorBase->EndIMEComposition();
}
nsresult
-EditorEventListener::Focus(nsIDOMEvent* aEvent)
+EditorEventListener::Focus(WidgetEvent* aFocusEvent)
{
- NS_ENSURE_TRUE(aEvent, NS_OK);
+ if (NS_WARN_IF(!aFocusEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
+
+ // XXX If aFocusEvent was created by chrome script, its defaultPrevented
+ // may be true, though. We shouldn't handle such event but we don't
+ // have a way to distinguish if coming event is created by chrome script.
+ NS_WARNING_ASSERTION(!aFocusEvent->DefaultPrevented(),
+ "eFocus event shouldn't be cancelable");
// Don't turn on selection and caret when the editor is disabled.
- if (mEditorBase->IsDisabled()) {
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ if (editorBase->IsDisabled()) {
return NS_OK;
}
// Spell check a textarea the first time that it is focused.
SpellCheckIfNeeded();
- if (!mEditorBase) {
+ if (!editorBase) {
// In e10s, this can cause us to flush notifications, which can destroy
// the node we're about to focus.
return NS_OK;
}
- nsCOMPtr<nsIDOMEventTarget> target;
- aEvent->GetTarget(getter_AddRefs(target));
+ nsCOMPtr<nsIDOMEventTarget> target = aFocusEvent->GetDOMEventTarget();
nsCOMPtr<nsINode> node = do_QueryInterface(target);
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
@@ -1087,7 +1131,7 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
// contenteditable editor. So, the editableRoot value is invalid for
// the plain text editor, and it will be set to the wrong limiter of
// the selection. However, fortunately, actual bugs are not found yet.
- nsCOMPtr<nsIContent> editableRoot = mEditorBase->FindSelectionRoot(node);
+ nsCOMPtr<nsIContent> editableRoot = editorBase->FindSelectionRoot(node);
// make sure that the element is really focused in case an earlier
// listener in the chain changed the focus.
@@ -1101,8 +1145,8 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
return NS_OK;
}
- nsCOMPtr<nsIDOMEventTarget> originalTarget;
- aEvent->GetOriginalTarget(getter_AddRefs(originalTarget));
+ nsCOMPtr<nsIDOMEventTarget> originalTarget =
+ aFocusEvent->GetOriginalDOMEventTarget();
nsCOMPtr<nsIContent> originalTargetAsContent =
do_QueryInterface(originalTarget);
@@ -1117,21 +1161,32 @@ EditorEventListener::Focus(nsIDOMEvent* aEvent)
}
}
- mEditorBase->OnFocus(target);
+ editorBase->OnFocus(target);
+ if (DetachedFromEditorOrDefaultPrevented(aFocusEvent)) {
+ return NS_OK;
+ }
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_OK);
- nsCOMPtr<nsIContent> focusedContent = mEditorBase->GetFocusedContentForIME();
+ nsCOMPtr<nsIContent> focusedContent = editorBase->GetFocusedContentForIME();
IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent,
- mEditorBase);
+ editorBase);
return NS_OK;
}
nsresult
-EditorEventListener::Blur(nsIDOMEvent* aEvent)
+EditorEventListener::Blur(WidgetEvent* aBlurEvent)
{
- NS_ENSURE_TRUE(aEvent, NS_OK);
+ if (NS_WARN_IF(!aBlurEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
+
+ // XXX If aBlurEvent was created by chrome script, its defaultPrevented
+ // may be true, though. We shouldn't handle such event but we don't
+ // have a way to distinguish if coming event is created by chrome script.
+ NS_WARNING_ASSERTION(!aBlurEvent->DefaultPrevented(),
+ "eBlur event shouldn't be cancelable");
// check if something else is focused. If another element is focused, then
// we should not change the selection.
@@ -1141,7 +1196,8 @@ EditorEventListener::Blur(nsIDOMEvent* aEvent)
nsCOMPtr<nsIDOMElement> element;
fm->GetFocusedElement(getter_AddRefs(element));
if (!element) {
- mEditorBase->FinalizeSelection();
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ editorBase->FinalizeSelection();
}
return NS_OK;
}
@@ -1149,20 +1205,26 @@ EditorEventListener::Blur(nsIDOMEvent* aEvent)
void
EditorEventListener::SpellCheckIfNeeded()
{
+ MOZ_ASSERT(!DetachedFromEditor());
+
// If the spell check skip flag is still enabled from creation time,
// disable it because focused editors are allowed to spell check.
+ RefPtr<EditorBase> editorBase(mEditorBase);
uint32_t currentFlags = 0;
- mEditorBase->GetFlags(&currentFlags);
+ editorBase->GetFlags(&currentFlags);
if(currentFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) {
currentFlags ^= nsIPlaintextEditor::eEditorSkipSpellCheck;
- mEditorBase->SetFlags(currentFlags);
+ editorBase->SetFlags(currentFlags);
}
}
bool
EditorEventListener::IsFileControlTextBox()
{
- Element* root = mEditorBase->GetRoot();
+ MOZ_ASSERT(!DetachedFromEditor());
+
+ RefPtr<EditorBase> editorBase(mEditorBase);
+ Element* root = editorBase->GetRoot();
if (!root || !root->ChromeOnlyAccess()) {
return false;
}
@@ -1177,6 +1239,8 @@ EditorEventListener::IsFileControlTextBox()
bool
EditorEventListener::ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent)
{
+ MOZ_ASSERT(!DetachedFromEditor());
+
// Only return true if the target of the event is a desendant of the active
// editing host in order to match the similar decision made in
// nsXBLWindowKeyHandler.
@@ -1192,13 +1256,14 @@ EditorEventListener::ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent)
return false;
}
+ RefPtr<EditorBase> editorBase(mEditorBase);
nsCOMPtr<nsIHTMLEditor> htmlEditor =
- do_QueryInterface(static_cast<nsIEditor*>(mEditorBase));
+ do_QueryInterface(static_cast<nsIEditor*>(editorBase));
if (!htmlEditor) {
return false;
}
- nsCOMPtr<nsIDocument> doc = mEditorBase->GetDocument();
+ nsCOMPtr<nsIDocument> doc = editorBase->GetDocument();
if (doc->HasFlag(NODE_IS_EDITABLE)) {
// Don't need to perform any checks in designMode documents.
return true;
diff --git a/editor/libeditor/EditorEventListener.h b/editor/libeditor/EditorEventListener.h
index 505b711c7..7244ebea4 100644
--- a/editor/libeditor/EditorEventListener.h
+++ b/editor/libeditor/EditorEventListener.h
@@ -6,6 +6,7 @@
#ifndef EditorEventListener_h
#define EditorEventListener_h
+#include "mozilla/EventForwards.h"
#include "nsCOMPtr.h"
#include "nsError.h"
#include "nsIDOMEventListener.h"
@@ -60,14 +61,14 @@ protected:
nsresult KeyUp(nsIDOMKeyEvent* aKeyEvent);
#endif
nsresult KeyPress(nsIDOMKeyEvent* aKeyEvent);
- nsresult HandleText(nsIDOMEvent* aTextEvent);
- nsresult HandleStartComposition(nsIDOMEvent* aCompositionEvent);
- void HandleEndComposition(nsIDOMEvent* aCompositionEvent);
+ nsresult HandleChangeComposition(WidgetCompositionEvent* aCompositionEvent);
+ nsresult HandleStartComposition(WidgetCompositionEvent* aCompositionEvent);
+ void HandleEndComposition(WidgetCompositionEvent* aCompositionEvent);
virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent);
virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) { return NS_OK; }
virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent);
- nsresult Focus(nsIDOMEvent* aEvent);
- nsresult Blur(nsIDOMEvent* aEvent);
+ nsresult Focus(WidgetEvent* aFocusEvent);
+ nsresult Blur(WidgetEvent* aBlurEvent);
nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
nsresult DragOver(nsIDOMDragEvent* aDragEvent);
nsresult DragExit(nsIDOMDragEvent* aDragEvent);
@@ -85,6 +86,19 @@ protected:
bool ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent);
nsresult HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent);
+ /**
+ * DetachedFromEditor() returns true if editor was detached.
+ * Otherwise, false.
+ */
+ bool DetachedFromEditor() const;
+
+ /**
+ * DetachedFromEditorOrDefaultPrevented() returns true if editor was detached
+ * and/or the event was consumed. Otherwise, i.e., attached editor can
+ * handle the event, returns true.
+ */
+ bool DetachedFromEditorOrDefaultPrevented(WidgetEvent* aEvent) const;
+
EditorBase* mEditorBase; // weak
RefPtr<nsCaret> mCaret;
bool mCommitText;
diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp
index dd47ffd3c..368f7a3e9 100644
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -5161,23 +5161,22 @@ HTMLEditor::OurWindowHasFocus()
}
bool
-HTMLEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
+HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
{
- if (!EditorBase::IsAcceptableInputEvent(aEvent)) {
+ if (!EditorBase::IsAcceptableInputEvent(aGUIEvent)) {
return false;
}
// While there is composition, all composition events in its top level window
// are always fired on the composing editor. Therefore, if this editor has
// composition, the composition events should be handled in this editor.
- if (mComposition && aEvent->WidgetEventPtr()->AsCompositionEvent()) {
+ if (mComposition && aGUIEvent->AsCompositionEvent()) {
return true;
}
NS_ENSURE_TRUE(mDocWeak, false);
- nsCOMPtr<nsIDOMEventTarget> target;
- aEvent->GetTarget(getter_AddRefs(target));
+ nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetDOMEventTarget();
NS_ENSURE_TRUE(target, false);
nsCOMPtr<nsIDocument> document = do_QueryReferent(mDocWeak);
@@ -5201,8 +5200,7 @@ HTMLEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
// If the event is a mouse event, we need to check if the target content is
// the focused editing host or its descendant.
- nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
- if (mouseEvent) {
+ if (aGUIEvent->AsMouseEventBase()) {
nsIContent* editingHost = GetActiveEditingHost();
// If there is no active editing host, we cannot handle the mouse event
// correctly.
diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h
index 477ec9741..dfcdd8d6b 100644
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -114,7 +114,7 @@ public:
virtual Element* GetEditorRoot() override;
virtual already_AddRefed<nsIContent> FindSelectionRoot(
nsINode *aNode) override;
- virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent) override;
+ virtual bool IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) override;
virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
virtual bool IsEditable(nsINode* aNode) override;
using EditorBase::IsEditable;
diff --git a/editor/libeditor/HTMLEditorEventListener.cpp b/editor/libeditor/HTMLEditorEventListener.cpp
index 8fb9459c2..aa767519c 100644
--- a/editor/libeditor/HTMLEditorEventListener.cpp
+++ b/editor/libeditor/HTMLEditorEventListener.cpp
@@ -7,6 +7,7 @@
#include "HTMLEditUtils.h"
#include "mozilla/HTMLEditor.h"
+#include "mozilla/MouseEvents.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/Selection.h"
#include "nsCOMPtr.h"
@@ -52,6 +53,12 @@ HTMLEditorEventListener::GetHTMLEditor()
nsresult
HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
{
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
+
+ // FYI: We need to notify HTML editor of mouseup even if it's consumed
+ // because HTML editor always needs to release grabbing resizer.
HTMLEditor* htmlEditor = GetHTMLEditor();
nsCOMPtr<nsIDOMEventTarget> target;
@@ -71,10 +78,17 @@ HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
nsresult
HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
+ if (NS_WARN_IF(!aMouseEvent) || DetachedFromEditor()) {
+ return NS_OK;
+ }
+
+ WidgetMouseEvent* mousedownEvent =
+ aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
+
HTMLEditor* htmlEditor = GetHTMLEditor();
// Contenteditable should disregard mousedowns outside it.
// IsAcceptableInputEvent() checks it for a mouse event.
- if (!htmlEditor->IsAcceptableInputEvent(aMouseEvent->AsEvent())) {
+ if (!htmlEditor->IsAcceptableInputEvent(mousedownEvent)) {
// If it's not acceptable mousedown event (including when mousedown event
// is fired outside of the active editing host), we need to commit
// composition because it will be change the selection to the clicked
@@ -82,6 +96,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
return EditorEventListener::MouseDown(aMouseEvent);
}
+ // XXX This method may change selection. So, we need to commit composition
+ // here, first.
+
// Detect only "context menu" click
// XXX This should be easier to do!
// But eDOMEvents_contextmenu and eContextMenu is not exposed in any event
@@ -103,7 +120,7 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
if (isContextClick || (buttonNumber == 0 && clickCount == 2)) {
- RefPtr<Selection> selection = mEditorBase->GetSelection();
+ RefPtr<Selection> selection = htmlEditor->GetSelection();
NS_ENSURE_TRUE(selection, NS_OK);
// Get location of mouse within target node
@@ -175,6 +192,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
} else {
htmlEditor->SelectElement(element);
}
+ if (DetachedFromEditor()) {
+ return NS_OK;
+ }
}
}
// HACK !!! Context click places the caret but the context menu consumes
diff --git a/editor/libeditor/TextEditor.cpp b/editor/libeditor/TextEditor.cpp
index 8fe824e11..d21585597 100644
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -834,17 +834,19 @@ TextEditor::BeginIMEComposition(WidgetCompositionEvent* aEvent)
}
nsresult
-TextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
+TextEditor::UpdateIMEComposition(WidgetCompositionEvent* aCompositionChangeEvent)
{
- MOZ_ASSERT(aDOMTextEvent, "aDOMTextEvent must not be nullptr");
+ MOZ_ASSERT(aCompsitionChangeEvent,
+ "aCompositionChangeEvent must not be nullptr");
- WidgetCompositionEvent* compositionChangeEvent =
- aDOMTextEvent->WidgetEventPtr()->AsCompositionEvent();
- NS_ENSURE_TRUE(compositionChangeEvent, NS_ERROR_INVALID_ARG);
- MOZ_ASSERT(compositionChangeEvent->mMessage == eCompositionChange,
- "The internal event should be eCompositionChange");
+ if (NS_WARN_IF(!aCompositionChangeEvent)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ MOZ_ASSERT(aCompositionChangeEvent->mMessage == eCompositionChange,
+ "The event should be eCompositionChange");
- if (!EnsureComposition(compositionChangeEvent)) {
+ if (!EnsureComposition(aCompositionChangeEvent)) {
return NS_OK;
}
@@ -865,7 +867,7 @@ TextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
MOZ_ASSERT(!mPlaceHolderBatch,
"UpdateIMEComposition() must be called without place holder batch");
TextComposition::CompositionChangeEventHandlingMarker
- compositionChangeEventHandlingMarker(mComposition, compositionChangeEvent);
+ compositionChangeEventHandlingMarker(mComposition, aCompositionChangeEvent);
NotifyEditorObservers(eNotifyEditorObserversOfBefore);
@@ -875,7 +877,7 @@ TextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
{
AutoPlaceHolderBatch batch(this, nsGkAtoms::IMETxnName);
- rv = InsertText(compositionChangeEvent->mData);
+ rv = InsertText(aCompositionChangeEvent->mData);
if (caretP) {
caretP->SetSelection(selection);
@@ -887,7 +889,7 @@ TextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
// compositionend event, we don't need to notify editor observes of this
// change.
// NOTE: We must notify after the auto batch will be gone.
- if (!compositionChangeEvent->IsFollowedByCompositionEnd()) {
+ if (!aCompositionChangeEvent->IsFollowedByCompositionEnd()) {
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
}
diff --git a/editor/libeditor/TextEditor.h b/editor/libeditor/TextEditor.h
index 872cd91d3..31c551f85 100644
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -130,7 +130,8 @@ public:
virtual already_AddRefed<dom::EventTarget> GetDOMEventTarget() override;
virtual nsresult BeginIMEComposition(WidgetCompositionEvent* aEvent) override;
- virtual nsresult UpdateIMEComposition(nsIDOMEvent* aTextEvent) override;
+ virtual nsresult UpdateIMEComposition(
+ WidgetCompositionEvent* aCompositionChangeEvent) override;
virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
diff --git a/hal/Hal.cpp b/hal/Hal.cpp
index 8ac9e6847..16201a2d8 100644
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -754,96 +754,6 @@ UnlockScreenOrientation()
PROXY_IF_SANDBOXED(UnlockScreenOrientation());
}
-void
-EnableSwitchNotifications(SwitchDevice aDevice) {
- AssertMainThread();
- PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
-}
-
-void
-DisableSwitchNotifications(SwitchDevice aDevice) {
- AssertMainThread();
- PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
-}
-
-SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
-{
- AssertMainThread();
- RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
-}
-
-void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
-{
- AssertMainThread();
- PROXY_IF_SANDBOXED(NotifySwitchStateFromInputDevice(aDevice, aState));
-}
-
-typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
-
-static SwitchObserverList *sSwitchObserverLists = nullptr;
-
-static SwitchObserverList&
-GetSwitchObserverList(SwitchDevice aDevice) {
- MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE);
- if (sSwitchObserverLists == nullptr) {
- sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
- }
- return sSwitchObserverLists[aDevice];
-}
-
-static void
-ReleaseObserversIfNeeded() {
- for (int i = 0; i < NUM_SWITCH_DEVICE; i++) {
- if (sSwitchObserverLists[i].Length() != 0)
- return;
- }
-
- //The length of every list is 0, no observer in the list.
- delete [] sSwitchObserverLists;
- sSwitchObserverLists = nullptr;
-}
-
-void
-RegisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
-{
- AssertMainThread();
- SwitchObserverList& observer = GetSwitchObserverList(aDevice);
- observer.AddObserver(aObserver);
- if (observer.Length() == 1) {
- EnableSwitchNotifications(aDevice);
- }
-}
-
-void
-UnregisterSwitchObserver(SwitchDevice aDevice, SwitchObserver *aObserver)
-{
- AssertMainThread();
-
- if (!sSwitchObserverLists) {
- return;
- }
-
- SwitchObserverList& observer = GetSwitchObserverList(aDevice);
- if (!observer.RemoveObserver(aObserver) || observer.Length() > 0) {
- return;
- }
-
- DisableSwitchNotifications(aDevice);
- ReleaseObserversIfNeeded();
-}
-
-void
-NotifySwitchChange(const SwitchEvent& aEvent)
-{
- // When callback this notification, main thread may call unregister function
- // first. We should check if this pointer is valid.
- if (!sSwitchObserverLists)
- return;
-
- SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
- observer.Broadcast(aEvent);
-}
-
static AlarmObserver* sAlarmObserver;
bool
diff --git a/hal/Hal.h b/hal/Hal.h
index e45bbcde2..224b4c451 100644
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -402,37 +402,6 @@ MOZ_MUST_USE bool LockScreenOrientation(const dom::ScreenOrientationInternal& aO
void UnlockScreenOrientation();
/**
- * Register an observer for the switch of given SwitchDevice.
- *
- * The observer will receive data whenever the data generated by the
- * given switch.
- */
-void RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aSwitchObserver);
-
-/**
- * Unregister an observer for the switch of given SwitchDevice.
- */
-void UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aSwitchObserver);
-
-/**
- * Notify the state of the switch.
- *
- * This API is internal to hal; clients shouldn't call it directly.
- */
-void NotifySwitchChange(const hal::SwitchEvent& aEvent);
-
-/**
- * Get current switch information.
- */
-hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice);
-
-/**
- * Notify switch status change from input device.
- */
-void NotifySwitchStateFromInputDevice(hal::SwitchDevice aDevice,
- hal::SwitchState aState);
-
-/**
* Register an observer that is notified when a programmed alarm
* expires.
*
diff --git a/hal/HalInternal.h b/hal/HalInternal.h
index d93023dd0..ea997c2f4 100644
--- a/hal/HalInternal.h
+++ b/hal/HalInternal.h
@@ -55,16 +55,6 @@ void EnableScreenConfigurationNotifications();
void DisableScreenConfigurationNotifications();
/**
- * Enable switch notifications from the backend
- */
-void EnableSwitchNotifications(hal::SwitchDevice aDevice);
-
-/**
- * Disable switch notifications from the backend
- */
-void DisableSwitchNotifications(hal::SwitchDevice aDevice);
-
-/**
* Enable alarm notifications from the backend.
*/
MOZ_MUST_USE bool EnableAlarm();
diff --git a/hal/HalTypes.h b/hal/HalTypes.h
index 5f0ad3ff7..dc29f0553 100644
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -33,26 +33,6 @@ enum ShutdownMode {
eHalShutdownMode_Count = 3
};
-class SwitchEvent;
-
-enum SwitchDevice {
- SWITCH_DEVICE_UNKNOWN = -1,
- SWITCH_HEADPHONES,
- SWITCH_USB,
- NUM_SWITCH_DEVICE
-};
-
-enum SwitchState {
- SWITCH_STATE_UNKNOWN = -1,
- SWITCH_STATE_ON,
- SWITCH_STATE_OFF,
- SWITCH_STATE_HEADSET, // Headphone with microphone
- SWITCH_STATE_HEADPHONE, // without microphone
- NUM_SWITCH_STATE
-};
-
-typedef Observer<SwitchEvent> SwitchObserver;
-
// Note that we rely on the order of this enum's entries. Higher priorities
// should have larger int values.
enum ProcessPriority {
@@ -141,28 +121,6 @@ struct ParamTraits<mozilla::hal::WakeLockControl>
mozilla::hal::NUM_WAKE_LOCK>
{};
-/**
- * Serializer for SwitchState
- */
-template <>
-struct ParamTraits<mozilla::hal::SwitchState>:
- public ContiguousEnumSerializer<
- mozilla::hal::SwitchState,
- mozilla::hal::SWITCH_STATE_UNKNOWN,
- mozilla::hal::NUM_SWITCH_STATE> {
-};
-
-/**
- * Serializer for SwitchDevice
- */
-template <>
-struct ParamTraits<mozilla::hal::SwitchDevice>:
- public ContiguousEnumSerializer<
- mozilla::hal::SwitchDevice,
- mozilla::hal::SWITCH_DEVICE_UNKNOWN,
- mozilla::hal::NUM_SWITCH_DEVICE> {
-};
-
template <>
struct ParamTraits<mozilla::hal::ProcessPriority>:
public ContiguousEnumSerializer<
diff --git a/hal/fallback/FallbackSwitch.cpp b/hal/fallback/FallbackSwitch.cpp
index e9b7eab0a..38d6a50e9 100644
--- a/hal/fallback/FallbackSwitch.cpp
+++ b/hal/fallback/FallbackSwitch.cpp
@@ -10,26 +10,6 @@ using namespace mozilla::hal;
namespace mozilla {
namespace hal_impl {
-void
-EnableSwitchNotifications(SwitchDevice aDevice)
-{
-}
-
-void
-DisableSwitchNotifications(SwitchDevice aDevice)
-{
-}
-
-SwitchState
-GetCurrentSwitchState(SwitchDevice aDevice) {
- return SWITCH_STATE_UNKNOWN;
-}
-
-void
-NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
-{
-}
-
bool IsHeadphoneEventFromInputDev()
{
return false;
diff --git a/hal/sandbox/PHal.ipdl b/hal/sandbox/PHal.ipdl
index 37b69f93f..1af550aff 100644
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -13,8 +13,6 @@ using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientatio
using mozilla::hal::SensorType from "mozilla/HalSensor.h";
using mozilla::hal::SensorAccuracyType from "mozilla/HalSensor.h";
using mozilla::hal::WakeLockControl from "mozilla/HalTypes.h";
-using mozilla::hal::SwitchState from "mozilla/HalTypes.h";
-using mozilla::hal::SwitchDevice from "mozilla/HalTypes.h";
using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
using nsIntRect from "nsRect.h";
using PRTime from "prtime.h";
@@ -41,11 +39,6 @@ struct NetworkInformation {
uint32_t dhcpGateway;
};
-struct SwitchEvent {
- SwitchDevice device;
- SwitchState status;
-};
-
struct WakeLockInformation {
nsString topic;
uint32_t numLocks;
@@ -80,7 +73,6 @@ child:
async NotifyNetworkChange(NetworkInformation aNetworkInfo);
async NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
async NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
- async NotifySwitchChange(SwitchEvent aEvent);
async NotifySystemClockChange(int64_t aClockDeltaMS);
async NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo);
@@ -138,11 +130,6 @@ parent:
returns (bool allowed);
async UnlockScreenOrientation();
- async EnableSwitchNotifications(SwitchDevice aDevice);
- async DisableSwitchNotifications(SwitchDevice aDevice);
- sync GetCurrentSwitchState(SwitchDevice aDevice)
- returns (SwitchState aState);
-
async FactoryReset(nsString aReason);
child:
diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp
index d33a53a2f..9771b3ef6 100644
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -300,34 +300,6 @@ GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
Hal()->SendGetWakeLockInfo(nsString(aTopic), aWakeLockInfo);
}
-void
-EnableSwitchNotifications(SwitchDevice aDevice)
-{
- Hal()->SendEnableSwitchNotifications(aDevice);
-}
-
-void
-DisableSwitchNotifications(SwitchDevice aDevice)
-{
- Hal()->SendDisableSwitchNotifications(aDevice);
-}
-
-SwitchState
-GetCurrentSwitchState(SwitchDevice aDevice)
-{
- SwitchState state;
- Hal()->SendGetCurrentSwitchState(aDevice, &state);
- return state;
-}
-
-void
-NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
-{
- Unused << aDevice;
- Unused << aState;
- NS_RUNTIMEABORT("Only the main process may notify switch state change.");
-}
-
bool
EnableAlarm()
{
@@ -420,7 +392,6 @@ class HalParent : public PHalParent
, public ISensorObserver
, public WakeLockObserver
, public ScreenConfigurationObserver
- , public SwitchObserver
, public SystemClockChangeObserver
, public SystemTimezoneChangeObserver
{
@@ -440,10 +411,6 @@ public:
hal::UnregisterWakeLockObserver(this);
hal::UnregisterSystemClockChangeObserver(this);
hal::UnregisterSystemTimezoneChangeObserver(this);
- for (int32_t switchDevice = SWITCH_DEVICE_UNKNOWN + 1;
- switchDevice < NUM_SWITCH_DEVICE; ++switchDevice) {
- hal::UnregisterSwitchObserver(SwitchDevice(switchDevice), this);
- }
}
virtual bool
@@ -771,34 +738,6 @@ public:
Unused << SendNotifyWakeLockChange(aWakeLockInfo);
}
- virtual bool
- RecvEnableSwitchNotifications(const SwitchDevice& aDevice) override
- {
- // Content has no reason to listen to switch events currently.
- hal::RegisterSwitchObserver(aDevice, this);
- return true;
- }
-
- virtual bool
- RecvDisableSwitchNotifications(const SwitchDevice& aDevice) override
- {
- hal::UnregisterSwitchObserver(aDevice, this);
- return true;
- }
-
- void Notify(const SwitchEvent& aSwitchEvent) override
- {
- Unused << SendNotifySwitchChange(aSwitchEvent);
- }
-
- virtual bool
- RecvGetCurrentSwitchState(const SwitchDevice& aDevice, hal::SwitchState *aState) override
- {
- // Content has no reason to listen to switch events currently.
- *aState = hal::GetCurrentSwitchState(aDevice);
- return true;
- }
-
void Notify(const int64_t& aClockDeltaMS) override
{
Unused << SendNotifySystemClockChange(aClockDeltaMS);
@@ -869,12 +808,6 @@ public:
}
virtual bool
- RecvNotifySwitchChange(const mozilla::hal::SwitchEvent& aEvent) override {
- hal::NotifySwitchChange(aEvent);
- return true;
- }
-
- virtual bool
RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) override {
hal::NotifySystemClockChange(aClockDeltaMS);
return true;
diff --git a/ipc/chromium/src/base/hash_tables.h b/ipc/chromium/src/base/hash_tables.h
index 956cadb3d..9e8d6b110 100644
--- a/ipc/chromium/src/base/hash_tables.h
+++ b/ipc/chromium/src/base/hash_tables.h
@@ -31,18 +31,14 @@
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wshadow"
-# if MOZ_GCC_VERSION_AT_LEAST(4, 9, 0)
-# pragma GCC diagnostic ignored "-Wshadow-local"
-# endif
+# pragma GCC diagnostic ignored "-Wshadow-local"
#endif
#include <hash_map>
#include <hash_set>
#ifdef __GNUC__
-# if MOZ_GCC_VERSION_AT_LEAST(4, 9, 0)
-# pragma GCC diagnostic pop // -Wshadow-local
-# endif
+# pragma GCC diagnostic pop // -Wshadow-local
# pragma GCC diagnostic pop // -Wshadow
#endif
diff --git a/layout/style/nsCSSPseudoElements.h b/layout/style/nsCSSPseudoElements.h
index eaf8d966b..acf818a2c 100644
--- a/layout/style/nsCSSPseudoElements.h
+++ b/layout/style/nsCSSPseudoElements.h
@@ -111,7 +111,7 @@ private:
// which is a general gcc bug that we seem to have hit only on Android/x86.
#if defined(ANDROID) && defined(__i386__) && defined(__GNUC__) && \
!defined(__clang__)
-#if (MOZ_GCC_VERSION_AT_LEAST(4,9,0) && MOZ_GCC_VERSION_AT_MOST(4,9,2))
+#if (MOZ_GCC_VERSION_AT_MOST(4,9,2))
__attribute__((noinline))
#endif
#endif
diff --git a/media/libwebp/AUTHORS b/media/libwebp/AUTHORS
index b6e9cfb89..83c7b9c5e 100644
--- a/media/libwebp/AUTHORS
+++ b/media/libwebp/AUTHORS
@@ -35,4 +35,5 @@ Contributors:
- Urvang Joshi (urvang at google dot com)
- Vikas Arora (vikasa at google dot com)
- Vincent Rabaud (vrabaud at google dot com)
+- Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
- Yang Zhang (yang dot zhang at arm dot com)
diff --git a/media/libwebp/MOZCHANGES b/media/libwebp/MOZCHANGES
deleted file mode 100644
index 68937eea6..000000000
--- a/media/libwebp/MOZCHANGES
+++ /dev/null
@@ -1,3 +0,0 @@
-Changes made to pristine libwebp source by mozilla.org developers.
-
-2017/01/27 -- Synced with libwebp-0.6.0 (bug #1294490).
diff --git a/media/libwebp/NEWS b/media/libwebp/NEWS
index 3bf4bd052..480cb7d34 100644
--- a/media/libwebp/NEWS
+++ b/media/libwebp/NEWS
@@ -1,3 +1,26 @@
+- 4/2/2018: version 1.0.0
+ This is a binary compatible release.
+ * lossy encoder improvements to avoid chroma shifts in various circumstances
+ (issues #308, #340)
+ * big-endian fixes for decode, RGBA import and WebPPictureDistortion
+ Tool updates:
+ gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
+ web browsers, transcoding tools (issue #379)
+ img2webp, webpmux - allow options to be passed in via a file (issue #355)
+
+- 11/24/2017: version 0.6.1
+ This is a binary compatible release.
+ * lossless performance and compression improvements + a new 'cruncher' mode
+ (-m 6 -q 100)
+ * ARM performance improvements with clang (15-20% w/ndk r15c, issue #339)
+ * webp-js: emscripten/webassembly based javascript decoder
+ * miscellaneous bug & build fixes (issue #329, #332, #343, #353, #360, #361,
+ #363)
+ Tool updates / additions:
+ added webpinfo - prints file format information (issue #330)
+ gif2webp - loop behavior modified to match Chrome M63+ (crbug.com/649264);
+ '-loop_compatibility' can be used for the old behavior
+
- 1/26/2017: version 0.6.0
* lossless performance and compression improvements
* miscellaneous performance improvements (SSE2, NEON, MSA)
diff --git a/media/libwebp/README b/media/libwebp/README
index 4c15c4ad8..a76b3787f 100644
--- a/media/libwebp/README
+++ b/media/libwebp/README
@@ -4,7 +4,7 @@
\__\__/\____/\_____/__/ ____ ___
/ _/ / \ \ / _ \/ _/
/ \_/ / / \ \ __/ \__
- \____/____/\_____/_____/____/v0.6.0
+ \____/____/\_____/_____/____/v1.0.0
Description:
============
@@ -113,8 +113,8 @@ make install
CMake:
------
-The support for CMake is minimal: it only helps you compile libwebp, cwebp and
-dwebp.
+With CMake, you can compile libwebp, cwebp, dwebp, gif2web, img2webp, webpinfo
+and the JS bindings.
Prerequisites:
A compiler (e.g., gcc with autotools) and CMake.
@@ -123,18 +123,25 @@ minimal build:
$ sudo apt-get install build-essential cmake
When building from git sources, you will need to run cmake to generate the
-configure script.
+makefiles.
mkdir build && cd build && cmake ../
make
make install
-If you also want cwebp or dwebp, you will need to enable them through CMake:
+If you also want any of the executables, you will need to enable them through
+CMake, e.g.:
cmake -DWEBP_BUILD_CWEBP=ON -DWEBP_BUILD_DWEBP=ON ../
or through your favorite interface (like ccmake or cmake-qt-gui).
+Finally, once installed, you can also use WebP in your CMake project by doing:
+
+find_package(WebP)
+
+which will define the CMake variables WebP_INCLUDE_DIRS and WebP_LIBRARIES.
+
Gradle:
-------
The support for Gradle is minimal: it only helps you compile libwebp, cwebp and
@@ -360,6 +367,23 @@ Use following options to convert into alternate image formats:
-quiet ....... quiet mode, don't print anything
-noasm ....... disable all assembly optimizations
+WebP file analysis tool:
+========================
+
+'webpinfo' can be used to print out the chunk level structure and bitstream
+header information of WebP files. It can also check if the files are of valid
+WebP format.
+
+Usage: webpinfo [options] in_files
+Note: there could be multiple input files;
+ options must come before input files.
+Options:
+ -version ........... Print version number and exit.
+ -quiet ............. Do not show chunk parsing information.
+ -diag .............. Show parsing error diagnosis.
+ -summary ........... Show chunk stats summary.
+ -bitstream_info .... Parse bitstream header.
+
Visualization tool:
===================
@@ -434,6 +458,7 @@ File-level options (only used at the start of compression):
-mixed ............... use mixed lossy/lossless automatic mode
-v ................... verbose mode
-h ................... this help
+ -version ............. print version number and exit
Per-frame options (only used for subsequent images input):
-d <int> ............. frame duration in ms (default: 100)
@@ -470,6 +495,8 @@ Options:
-metadata <string> ..... comma separated list of metadata to
copy from the input to the output if present
Valid values: all, none, icc, xmp (default)
+ -loop_compatibility .... use compatibility mode for Chrome
+ version prior to M62 (inclusive)
-mt .................... use multi-threading if available
-version ............... print version number and exit
@@ -498,6 +525,11 @@ Options:
-min_psnr <float> ... minimum per-frame PSNR
-raw_comparison ..... if this flag is not used, RGB is
premultiplied before comparison
+ -max_diff <int> ..... maximum allowed difference per channel
+ between corresponding pixels in subsequent
+ frames
+ -h .................. this help
+ -version ............ print version number and exit
Building:
---------
diff --git a/media/libwebp/README.mux b/media/libwebp/README.mux
index 04fedd163..bd4f92fa3 100644
--- a/media/libwebp/README.mux
+++ b/media/libwebp/README.mux
@@ -1,7 +1,7 @@
 __ __ ____ ____ ____ __ __ _ __ __
/ \\/ \/ _ \/ _ \/ _ \/ \ \/ \___/_ / _\
\ / __/ _ \ __/ / / (_/ /__
- \__\__/\_____/_____/__/ \__//_/\_____/__/___/v0.4.0
+ \__\__/\_____/_____/__/ \__//_/\_____/__/___/v1.0.0
Description:
@@ -33,6 +33,7 @@ Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
webpmux -info INPUT
webpmux [-h|-help]
webpmux -version
+ webpmux argument_file_name
GET_OPTIONS:
Extract relevant data:
@@ -92,6 +93,9 @@ INPUT & OUTPUT are in WebP format.
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
valid.
+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 '-'.
+
Visualization tool:
===================
diff --git a/media/libwebp/UXPCHANGES b/media/libwebp/UXPCHANGES
new file mode 100644
index 000000000..8c3eb5ad2
--- /dev/null
+++ b/media/libwebp/UXPCHANGES
@@ -0,0 +1,4 @@
+Changes made to pristine libwebp source by Moonchild Productions and mozilla.org developers.
+
+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.
diff --git a/media/libwebp/dec/alpha_dec.c b/media/libwebp/dec/alpha_dec.c
index 83ffd4b60..1ff7c62d8 100644
--- a/media/libwebp/dec/alpha_dec.c
+++ b/media/libwebp/dec/alpha_dec.c
@@ -12,9 +12,9 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
-#include "./alphai_dec.h"
-#include "./vp8i_dec.h"
-#include "./vp8li_dec.h"
+#include "../dec/alphai_dec.h"
+#include "../dec/vp8i_dec.h"
+#include "../dec/vp8li_dec.h"
#include "../dsp/dsp.h"
#include "../utils/quant_levels_dec_utils.h"
#include "../utils/utils.h"
diff --git a/media/libwebp/dec/alphai_dec.h b/media/libwebp/dec/alphai_dec.h
index 561e8151e..3b40691b5 100644
--- a/media/libwebp/dec/alphai_dec.h
+++ b/media/libwebp/dec/alphai_dec.h
@@ -11,10 +11,10 @@
//
// Author: Urvang (urvang@google.com)
-#ifndef WEBP_DEC_ALPHAI_H_
-#define WEBP_DEC_ALPHAI_H_
+#ifndef WEBP_DEC_ALPHAI_DEC_H_
+#define WEBP_DEC_ALPHAI_DEC_H_
-#include "./webpi_dec.h"
+#include "../dec/webpi_dec.h"
#include "../utils/filters_utils.h"
#ifdef __cplusplus
@@ -51,4 +51,4 @@ void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
} // extern "C"
#endif
-#endif /* WEBP_DEC_ALPHAI_H_ */
+#endif /* WEBP_DEC_ALPHAI_DEC_H_ */
diff --git a/media/libwebp/dec/buffer_dec.c b/media/libwebp/dec/buffer_dec.c
index c685fd564..d72d32b0a 100644
--- a/media/libwebp/dec/buffer_dec.c
+++ b/media/libwebp/dec/buffer_dec.c
@@ -13,15 +13,15 @@
#include <stdlib.h>
-#include "./vp8i_dec.h"
-#include "./webpi_dec.h"
+#include "../dec/vp8i_dec.h"
+#include "../dec/webpi_dec.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
// WebPDecBuffer
// Number of bytes per pixel for the different color-spaces.
-static const int kModeBpp[MODE_LAST] = {
+static const uint8_t kModeBpp[MODE_LAST] = {
3, 4, 3, 4, 4, 2, 2,
4, 4, 4, 2, // pre-multiplied modes
1, 1 };
@@ -36,7 +36,7 @@ static int IsValidColorspace(int webp_csp_mode) {
// strictly speaking, the very last (or first, if flipped) row
// doesn't require padding.
#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
- (uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)
+ ((uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH))
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
int ok = 1;
@@ -74,7 +74,8 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
} else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
const int stride = abs(buf->stride);
- const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
+ const uint64_t size =
+ MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
ok &= (size <= buf->size);
ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
@@ -98,9 +99,14 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
uint64_t uv_size = 0, a_size = 0, total_size;
// We need memory and it hasn't been allocated yet.
// => initialize output buffer, now that dimensions are known.
- const int stride = w * kModeBpp[mode];
- const uint64_t size = (uint64_t)stride * h;
+ int stride;
+ uint64_t size;
+ if ((uint64_t)w * kModeBpp[mode] >= (1ull << 32)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ stride = w * kModeBpp[mode];
+ size = (uint64_t)stride * h;
if (!WebPIsRGBMode(mode)) {
uv_stride = (w + 1) / 2;
uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
@@ -169,11 +175,11 @@ VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
return VP8_STATUS_OK;
}
-VP8StatusCode WebPAllocateDecBuffer(int w, int h,
+VP8StatusCode WebPAllocateDecBuffer(int width, int height,
const WebPDecoderOptions* const options,
- WebPDecBuffer* const out) {
+ WebPDecBuffer* const buffer) {
VP8StatusCode status;
- if (out == NULL || w <= 0 || h <= 0) {
+ if (buffer == NULL || width <= 0 || height <= 0) {
return VP8_STATUS_INVALID_PARAM;
}
if (options != NULL) { // First, apply options if there is any.
@@ -182,33 +188,39 @@ VP8StatusCode WebPAllocateDecBuffer(int w, int h,
const int ch = options->crop_height;
const int x = options->crop_left & ~1;
const int y = options->crop_top & ~1;
- if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
+ if (x < 0 || y < 0 || cw <= 0 || ch <= 0 ||
+ x + cw > width || y + ch > height) {
return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
}
- w = cw;
- h = ch;
+ width = cw;
+ height = ch;
}
+
if (options->use_scaling) {
+#if !defined(WEBP_REDUCE_SIZE)
int scaled_width = options->scaled_width;
int scaled_height = options->scaled_height;
if (!WebPRescalerGetScaledDimensions(
- w, h, &scaled_width, &scaled_height)) {
+ width, height, &scaled_width, &scaled_height)) {
return VP8_STATUS_INVALID_PARAM;
}
- w = scaled_width;
- h = scaled_height;
+ width = scaled_width;
+ height = scaled_height;
+#else
+ return VP8_STATUS_INVALID_PARAM; // rescaling not supported
+#endif
}
}
- out->width = w;
- out->height = h;
+ buffer->width = width;
+ buffer->height = height;
// Then, allocate buffer for real.
- status = AllocateBuffer(out);
+ status = AllocateBuffer(buffer);
if (status != VP8_STATUS_OK) return status;
// Use the stride trick if vertical flip is needed.
if (options != NULL && options->flip) {
- status = WebPFlipBuffer(out);
+ status = WebPFlipBuffer(buffer);
}
return status;
}
diff --git a/media/libwebp/dec/common_dec.h b/media/libwebp/dec/common_dec.h
index 6961e2247..9995f1a51 100644
--- a/media/libwebp/dec/common_dec.h
+++ b/media/libwebp/dec/common_dec.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_DEC_COMMON_H_
-#define WEBP_DEC_COMMON_H_
+#ifndef WEBP_DEC_COMMON_DEC_H_
+#define WEBP_DEC_COMMON_DEC_H_
// intra prediction modes
enum { B_DC_PRED = 0, // 4x4 modes
@@ -51,4 +51,4 @@ enum { MB_FEATURE_TREE_PROBS = 3,
NUM_PROBAS = 11
};
-#endif // WEBP_DEC_COMMON_H_
+#endif // WEBP_DEC_COMMON_DEC_H_
diff --git a/media/libwebp/dec/frame_dec.c b/media/libwebp/dec/frame_dec.c
index f91e27f7c..57e4d9669 100644
--- a/media/libwebp/dec/frame_dec.c
+++ b/media/libwebp/dec/frame_dec.c
@@ -12,13 +12,13 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
-#include "./vp8i_dec.h"
+#include "../dec/vp8i_dec.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Main reconstruction function.
-static const int kScan[16] = {
+static const uint16_t kScan[16] = {
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
@@ -320,7 +320,7 @@ static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
#define MIN_DITHER_AMP 4
#define DITHER_AMP_TAB_SIZE 12
-static const int kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
+static const uint8_t kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
// roughly, it's dqm->uv_mat_[1]
8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
};
@@ -400,7 +400,9 @@ static void DitherRow(VP8Decoder* const dec) {
#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB
// Finalize and transmit a complete row. Return false in case of user-abort.
-static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
+static int FinishRow(void* arg1, void* arg2) {
+ VP8Decoder* const dec = (VP8Decoder*)arg1;
+ VP8Io* const io = (VP8Io*)arg2;
int ok = 1;
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
const int cache_id = ctx->id_;
@@ -448,10 +450,9 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
if (y_end > io->crop_bottom) {
y_end = io->crop_bottom; // make sure we don't overflow on last row.
}
+ // If dec->alpha_data_ is not NULL, we have some alpha plane present.
io->a = NULL;
if (dec->alpha_data_ != NULL && y_start < y_end) {
- // TODO(skal): testing presence of alpha with dec->alpha_data_ is not a
- // good idea.
io->a = VP8DecompressAlphaRows(dec, io, y_start, y_end - y_start);
if (io->a == NULL) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
@@ -558,7 +559,6 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
if (io->bypass_filtering) {
dec->filter_type_ = 0;
}
- // TODO(skal): filter type / strength / sharpness forcing
// Define the area where we can skip in-loop filtering, in case of cropping.
//
@@ -569,8 +569,6 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// Means: there's a dependency chain that goes all the way up to the
// top-left corner of the picture (MB #0). We must filter all the previous
// macroblocks.
- // TODO(skal): add an 'approximate_decoding' option, that won't produce
- // a 1:1 bit-exactness for complex filtering?
{
const int extra_pixels = kFilterExtraRows[dec->filter_type_];
if (dec->filter_type_ == 2) {
@@ -651,7 +649,7 @@ static int InitThreadContext(VP8Decoder* const dec) {
}
worker->data1 = dec;
worker->data2 = (void*)&dec->thread_ctx_.io_;
- worker->hook = (WebPWorkerHook)FinishRow;
+ worker->hook = FinishRow;
dec->num_caches_ =
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
} else {
@@ -728,7 +726,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
}
mem = (uint8_t*)dec->mem_;
- dec->intra_t_ = (uint8_t*)mem;
+ dec->intra_t_ = mem;
mem += intra_pred_mode_size;
dec->yuv_t_ = (VP8TopSamples*)mem;
@@ -750,7 +748,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
mem = (uint8_t*)WEBP_ALIGN(mem);
assert((yuv_size & WEBP_ALIGN_CST) == 0);
- dec->yuv_b_ = (uint8_t*)mem;
+ dec->yuv_b_ = mem;
mem += yuv_size;
dec->mb_data_ = (VP8MBData*)mem;
@@ -766,7 +764,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
const int extra_rows = kFilterExtraRows[dec->filter_type_];
const int extra_y = extra_rows * dec->cache_y_stride_;
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
- dec->cache_y_ = ((uint8_t*)mem) + extra_y;
+ dec->cache_y_ = mem + extra_y;
dec->cache_u_ = dec->cache_y_
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv;
dec->cache_v_ = dec->cache_u_
@@ -776,7 +774,7 @@ static int AllocateMemory(VP8Decoder* const dec) {
mem += cache_size;
// alpha plane
- dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
+ dec->alpha_plane_ = alpha_size ? mem : NULL;
mem += alpha_size;
assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
diff --git a/media/libwebp/dec/idec_dec.c b/media/libwebp/dec/idec_dec.c
index 78fb2e718..c9506bc83 100644
--- a/media/libwebp/dec/idec_dec.c
+++ b/media/libwebp/dec/idec_dec.c
@@ -15,9 +15,9 @@
#include <string.h>
#include <stdlib.h>
-#include "./alphai_dec.h"
-#include "./webpi_dec.h"
-#include "./vp8i_dec.h"
+#include "../dec/alphai_dec.h"
+#include "../dec/webpi_dec.h"
+#include "../dec/vp8i_dec.h"
#include "../utils/utils.h"
// In append mode, buffer allocations increase as multiples of this value.
@@ -283,10 +283,8 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
- VP8Io* const io = &idec->io_;
- if (io->teardown != NULL) {
- io->teardown(io);
- }
+ // Synchronize the thread, clean-up and check for errors.
+ VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
}
idec->state_ = STATE_ERROR;
return error;
@@ -673,12 +671,12 @@ void WebPIDelete(WebPIDecoder* idec) {
//------------------------------------------------------------------------------
// Wrapper toward WebPINewDecoder
-WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
+WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
size_t output_buffer_size, int output_stride) {
const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
WebPIDecoder* idec;
- if (mode >= MODE_YUV) return NULL;
+ if (csp >= MODE_YUV) return NULL;
if (is_external_memory == 0) { // Overwrite parameters to sane values.
output_buffer_size = 0;
output_stride = 0;
@@ -689,7 +687,7 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
}
idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL;
- idec->output_.colorspace = mode;
+ idec->output_.colorspace = csp;
idec->output_.is_external_memory = is_external_memory;
idec->output_.u.RGBA.rgba = output_buffer;
idec->output_.u.RGBA.stride = output_stride;
diff --git a/media/libwebp/dec/io_dec.c b/media/libwebp/dec/io_dec.c
index 8bfab8695..0edd9f526 100644
--- a/media/libwebp/dec/io_dec.c
+++ b/media/libwebp/dec/io_dec.c
@@ -14,7 +14,7 @@
#include <assert.h>
#include <stdlib.h>
#include "../dec/vp8i_dec.h"
-#include "./webpi_dec.h"
+#include "../dec/webpi_dec.h"
#include "../dsp/dsp.h"
#include "../dsp/yuv.h"
#include "../utils/utils.h"
@@ -212,7 +212,7 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
int num_rows;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba;
#else
uint8_t* alpha_dst = base_rgba + 1;
@@ -241,6 +241,7 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
//------------------------------------------------------------------------------
// YUV rescaling (no final RGB conversion needed)
+#if !defined(WEBP_REDUCE_SIZE)
static int Rescale(const uint8_t* src, int src_stride,
int new_lines, WebPRescaler* const wrk) {
int num_lines_out = 0;
@@ -431,7 +432,7 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
uint8_t* alpha_dst = base_rgba;
#else
uint8_t* alpha_dst = base_rgba + 1;
@@ -541,6 +542,8 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
return 1;
}
+#endif // WEBP_REDUCE_SIZE
+
//------------------------------------------------------------------------------
// Default custom functions
@@ -561,10 +564,14 @@ static int CustomSetup(VP8Io* io) {
WebPInitUpsamplers();
}
if (io->use_scaling) {
+#if !defined(WEBP_REDUCE_SIZE)
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
if (!ok) {
return 0; // memory error
}
+#else
+ return 0; // rescaling support not compiled
+#endif
} else {
if (is_rgb) {
WebPInitSamplers();
@@ -598,9 +605,6 @@ static int CustomSetup(VP8Io* io) {
}
}
- if (is_rgb) {
- VP8YUVInit();
- }
return 1;
}
diff --git a/media/libwebp/dec/quant_dec.c b/media/libwebp/dec/quant_dec.c
index 14e319894..6ecaf1c45 100644
--- a/media/libwebp/dec/quant_dec.c
+++ b/media/libwebp/dec/quant_dec.c
@@ -11,7 +11,7 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./vp8i_dec.h"
+#include "../dec/vp8i_dec.h"
static WEBP_INLINE int clip(int v, int M) {
return v < 0 ? 0 : v > M ? M : v;
diff --git a/media/libwebp/dec/tree_dec.c b/media/libwebp/dec/tree_dec.c
index 9e805f60f..581886025 100644
--- a/media/libwebp/dec/tree_dec.c
+++ b/media/libwebp/dec/tree_dec.c
@@ -11,15 +11,19 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./vp8i_dec.h"
+#include "../dec/vp8i_dec.h"
#include "../utils/bit_reader_inl_utils.h"
+#if !defined(USE_GENERIC_TREE)
#if !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__)
// using a table is ~1-2% slower on ARM. Prefer the coded-tree approach then.
-#define USE_GENERIC_TREE
+#define USE_GENERIC_TREE 1 // ALTERNATE_CODE
+#else
+#define USE_GENERIC_TREE 0
#endif
+#endif // USE_GENERIC_TREE
-#ifdef USE_GENERIC_TREE
+#if (USE_GENERIC_TREE == 1)
static const int8_t kYModesIntra4[18] = {
-B_DC_PRED, 1,
-B_TM_PRED, 2,
@@ -317,7 +321,7 @@ static void ParseIntraMode(VP8BitReader* const br,
int x;
for (x = 0; x < 4; ++x) {
const uint8_t* const prob = kBModesProba[top[x]][ymode];
-#ifdef USE_GENERIC_TREE
+#if (USE_GENERIC_TREE == 1)
// Generic tree-parsing
int i = kYModesIntra4[VP8GetBit(br, prob[0])];
while (i > 0) {
@@ -335,7 +339,7 @@ static void ParseIntraMode(VP8BitReader* const br,
(!VP8GetBit(br, prob[6]) ? B_LD_PRED :
(!VP8GetBit(br, prob[7]) ? B_VL_PRED :
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
-#endif // USE_GENERIC_TREE
+#endif // USE_GENERIC_TREE
top[x] = ymode;
}
memcpy(modes, top, 4 * sizeof(*top));
@@ -498,7 +502,7 @@ static const uint8_t
// Paragraph 9.9
-static const int kBands[16 + 1] = {
+static const uint8_t kBands[16 + 1] = {
0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
0 // extra entry as sentinel
};
diff --git a/media/libwebp/dec/vp8_dec.c b/media/libwebp/dec/vp8_dec.c
index fad8d9cf3..e7958be6b 100644
--- a/media/libwebp/dec/vp8_dec.c
+++ b/media/libwebp/dec/vp8_dec.c
@@ -13,10 +13,10 @@
#include <stdlib.h>
-#include "./alphai_dec.h"
-#include "./vp8i_dec.h"
-#include "./vp8li_dec.h"
-#include "./webpi_dec.h"
+#include "../dec/alphai_dec.h"
+#include "../dec/vp8i_dec.h"
+#include "../dec/vp8li_dec.h"
+#include "../dec/webpi_dec.h"
#include "../utils/bit_reader_inl_utils.h"
#include "../utils/utils.h"
@@ -491,7 +491,7 @@ static int GetCoeffsAlt(VP8BitReader* const br,
return 16;
}
-WEBP_TSAN_IGNORE_FUNCTION static void InitGetCoeffs(void) {
+static WEBP_TSAN_IGNORE_FUNCTION void InitGetCoeffs(void) {
if (GetCoeffs == NULL) {
if (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kSlowSSSE3)) {
GetCoeffs = GetCoeffsAlt;
diff --git a/media/libwebp/dec/vp8_dec.h b/media/libwebp/dec/vp8_dec.h
index b9337bbec..7b4941d65 100644
--- a/media/libwebp/dec/vp8_dec.h
+++ b/media/libwebp/dec/vp8_dec.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_WEBP_DECODE_VP8_H_
-#define WEBP_WEBP_DECODE_VP8_H_
+#ifndef WEBP_DEC_VP8_DEC_H_
+#define WEBP_DEC_VP8_DEC_H_
#include "../webp/decode.h"
@@ -33,7 +33,7 @@ extern "C" {
// /* customize io's functions (setup()/put()/teardown()) if needed. */
//
// VP8Decoder* dec = VP8New();
-// bool ok = VP8Decode(dec);
+// int ok = VP8Decode(dec, &io);
// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
// VP8Delete(dec);
// return ok;
@@ -157,24 +157,24 @@ void VP8Delete(VP8Decoder* const dec);
// Miscellaneous VP8/VP8L bitstream probing functions.
// Returns true if the next 3 bytes in data contain the VP8 signature.
-WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size);
+WEBP_EXTERN int VP8CheckSignature(const uint8_t* const data, size_t data_size);
// Validates the VP8 data-header and retrieves basic header information viz
// width and height. Returns 0 in case of formatting error. *width/*height
// can be passed NULL.
-WEBP_EXTERN(int) VP8GetInfo(
+WEBP_EXTERN int VP8GetInfo(
const uint8_t* data,
size_t data_size, // data available so far
size_t chunk_size, // total data size expected in the chunk
int* const width, int* const height);
// Returns true if the next byte(s) in data is a VP8L signature.
-WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size);
+WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const data, size_t size);
// Validates the VP8L data-header and retrieves basic header information viz
// width, height and alpha. Returns 0 in case of formatting error.
// width/height/has_alpha can be passed NULL.
-WEBP_EXTERN(int) VP8LGetInfo(
+WEBP_EXTERN int VP8LGetInfo(
const uint8_t* data, size_t data_size, // data available so far
int* const width, int* const height, int* const has_alpha);
@@ -182,4 +182,4 @@ WEBP_EXTERN(int) VP8LGetInfo(
} // extern "C"
#endif
-#endif /* WEBP_WEBP_DECODE_VP8_H_ */
+#endif /* WEBP_DEC_VP8_DEC_H_ */
diff --git a/media/libwebp/dec/vp8i_dec.h b/media/libwebp/dec/vp8i_dec.h
index 555853e8f..d0ef67b91 100644
--- a/media/libwebp/dec/vp8i_dec.h
+++ b/media/libwebp/dec/vp8i_dec.h
@@ -11,12 +11,12 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_DEC_VP8I_H_
-#define WEBP_DEC_VP8I_H_
+#ifndef WEBP_DEC_VP8I_DEC_H_
+#define WEBP_DEC_VP8I_DEC_H_
#include <string.h> // for memcpy()
-#include "./common_dec.h"
-#include "./vp8li_dec.h"
+#include "../dec/common_dec.h"
+#include "../dec/vp8li_dec.h"
#include "../utils/bit_reader_utils.h"
#include "../utils/random_utils.h"
#include "../utils/thread_utils.h"
@@ -30,8 +30,8 @@ extern "C" {
// Various defines and enums
// version numbers
-#define DEC_MAJ_VERSION 0
-#define DEC_MIN_VERSION 6
+#define DEC_MAJ_VERSION 1
+#define DEC_MIN_VERSION 0
#define DEC_REV_VERSION 0
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
@@ -57,7 +57,6 @@ extern "C" {
// '|' = left sample, '-' = top sample, '+' = top-left sample
// 't' = extra top-right sample for 4x4 modes
#define YUV_SIZE (BPS * 17 + BPS * 9)
-#define Y_SIZE (BPS * 17)
#define Y_OFF (BPS * 1 + 8)
#define U_OFF (Y_OFF + BPS * 16 + BPS)
#define V_OFF (U_OFF + 16)
@@ -317,4 +316,4 @@ const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8I_H_ */
+#endif /* WEBP_DEC_VP8I_DEC_H_ */
diff --git a/media/libwebp/dec/vp8l_dec.c b/media/libwebp/dec/vp8l_dec.c
index ef359a91f..3d303fb22 100644
--- a/media/libwebp/dec/vp8l_dec.c
+++ b/media/libwebp/dec/vp8l_dec.c
@@ -14,8 +14,8 @@
#include <stdlib.h>
-#include "./alphai_dec.h"
-#include "./vp8li_dec.h"
+#include "../dec/alphai_dec.h"
+#include "../dec/vp8li_dec.h"
#include "../dsp/dsp.h"
#include "../dsp/lossless.h"
#include "../dsp/lossless_common.h"
@@ -28,8 +28,8 @@
static const int kCodeLengthLiterals = 16;
static const int kCodeLengthRepeatCode = 16;
-static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
-static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
+static const uint8_t kCodeLengthExtraBits[3] = { 2, 3, 7 };
+static const uint8_t kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
// -----------------------------------------------------------------------------
// Five Huffman codes are used at each meta code:
@@ -86,7 +86,7 @@ static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
// All values computed for 8-bit first level lookup with Mark Adler's tool:
// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
#define FIXED_TABLE_SIZE (630 * 3 + 410)
-static const int kTableSize[12] = {
+static const uint16_t kTableSize[12] = {
FIXED_TABLE_SIZE + 654,
FIXED_TABLE_SIZE + 656,
FIXED_TABLE_SIZE + 658,
@@ -359,12 +359,14 @@ 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;
HuffmanCode* huffman_tables = NULL;
HuffmanCode* next = NULL;
int num_htree_groups = 1;
+ int num_htree_groups_limit = 1;
int max_alphabet_size = 0;
int* code_lengths = NULL;
const int table_size = kTableSize[color_cache_bits];
@@ -388,6 +390,18 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
num_htree_groups = group + 1;
}
}
+ // Check the validity of num_htree_groups. 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
+ // 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_;
+ } else {
+ num_htree_groups_limit = num_htree_groups;
+ }
}
if (br->eos_) goto Error;
@@ -403,68 +417,86 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
}
}
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
- sizeof(*huffman_tables));
- htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
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;
+ }
- 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; ++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];
+ 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;
}
- max_bits += local_max_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;
+ 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;
+ }
}
+ htree_group->use_packed_table =
+ !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
+ if (htree_group->use_packed_table) BuildPackedTable(htree_group);
}
- 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;
+ }
+ } while (i != num_htree_groups);
WebPSafeFree(code_lengths);
// All OK. Finalize pointers and return.
@@ -485,6 +517,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
//------------------------------------------------------------------------------
// Scaling.
+#if !defined(WEBP_REDUCE_SIZE)
static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
const int num_channels = 4;
const int in_width = io->mb_w;
@@ -516,10 +549,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
out_width, out_height, 0, num_channels, work);
return 1;
}
+#endif // WEBP_REDUCE_SIZE
//------------------------------------------------------------------------------
// Export to ARGB
+#if !defined(WEBP_REDUCE_SIZE)
+
// We have special "export" function since we need to convert from BGRA
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int rgba_stride, uint8_t* const rgba) {
@@ -561,6 +597,8 @@ static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
return num_lines_out;
}
+#endif // WEBP_REDUCE_SIZE
+
// Emit rows without any scaling.
static int EmitRows(WEBP_CSP_MODE colorspace,
const uint8_t* row_in, int in_stride,
@@ -746,9 +784,12 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
const WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
- const int num_rows_out = io->use_scaling ?
+ const int num_rows_out =
+#if !defined(WEBP_REDUCE_SIZE)
+ io->use_scaling ?
EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
rgba, buf->stride) :
+#endif // WEBP_REDUCE_SIZE
EmitRows(output->colorspace, rows_data, in_stride,
io->mb_w, io->mb_h, rgba, buf->stride);
// Update 'last_out_row_'.
@@ -1012,12 +1053,13 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
ok = 0;
goto End;
}
- assert(br->eos_ == VP8LIsEndOfStream(br));
+ br->eos_ = VP8LIsEndOfStream(br);
}
// Process the remaining rows corresponding to last row-block.
ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
End:
+ br->eos_ = VP8LIsEndOfStream(br);
if (!ok || (br->eos_ && pos < end)) {
ok = 0;
dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
@@ -1090,11 +1132,12 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br);
if (htree_group->use_packed_table) {
code = ReadPackedSymbols(htree_group, br, src);
+ if (VP8LIsEndOfStream(br)) break;
if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
} else {
code = ReadSymbol(htree_group->htrees[GREEN], br);
}
- if (br->eos_) break; // early out
+ if (VP8LIsEndOfStream(br)) break;
if (code < NUM_LITERAL_CODES) { // Literal
if (htree_group->is_trivial_literal) {
*src = htree_group->literal_arb | (code << 8);
@@ -1104,7 +1147,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br);
blue = ReadSymbol(htree_group->htrees[BLUE], br);
alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
- if (br->eos_) break;
+ if (VP8LIsEndOfStream(br)) break;
*src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
}
AdvanceByOne:
@@ -1132,7 +1175,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
VP8LFillBitWindow(br);
dist_code = GetCopyDistance(dist_symbol, br);
dist = PlaneCodeToDistance(width, dist_code);
- if (br->eos_) break;
+ if (VP8LIsEndOfStream(br)) break;
if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
goto Error;
} else {
@@ -1169,9 +1212,9 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
} else { // Not reached
goto Error;
}
- assert(br->eos_ == VP8LIsEndOfStream(br));
}
+ br->eos_ = VP8LIsEndOfStream(br);
if (dec->incremental_ && br->eos_ && src < src_end) {
RestoreState(dec);
} else if (!br->eos_) {
@@ -1630,12 +1673,19 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
+#if !defined(WEBP_REDUCE_SIZE)
if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
-
+#else
+ if (io->use_scaling) {
+ dec->status_ = VP8_STATUS_INVALID_PARAM;
+ goto Err;
+ }
+#endif
if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
// need the alpha-multiply functions for premultiplied output or rescaling
WebPInitAlphaProcessing();
}
+
if (!WebPIsRGBMode(dec->output_->colorspace)) {
WebPInitConvertARGBToYUV();
if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();
diff --git a/media/libwebp/dec/vp8li_dec.h b/media/libwebp/dec/vp8li_dec.h
index 097a9d058..ed89a02a9 100644
--- a/media/libwebp/dec/vp8li_dec.h
+++ b/media/libwebp/dec/vp8li_dec.h
@@ -12,11 +12,11 @@
// Author: Skal (pascal.massimino@gmail.com)
// Vikas Arora(vikaas.arora@gmail.com)
-#ifndef WEBP_DEC_VP8LI_H_
-#define WEBP_DEC_VP8LI_H_
+#ifndef WEBP_DEC_VP8LI_DEC_H_
+#define WEBP_DEC_VP8LI_DEC_H_
#include <string.h> // for memcpy()
-#include "./webpi_dec.h"
+#include "../dec/webpi_dec.h"
#include "../utils/bit_reader_utils.h"
#include "../utils/color_cache_utils.h"
#include "../utils/huffman_utils.h"
@@ -132,4 +132,4 @@ void VP8LDelete(VP8LDecoder* const dec);
} // extern "C"
#endif
-#endif /* WEBP_DEC_VP8LI_H_ */
+#endif /* WEBP_DEC_VP8LI_DEC_H_ */
diff --git a/media/libwebp/dec/webp_dec.c b/media/libwebp/dec/webp_dec.c
index a8e9c2c51..89c264d0a 100644
--- a/media/libwebp/dec/webp_dec.c
+++ b/media/libwebp/dec/webp_dec.c
@@ -13,9 +13,9 @@
#include <stdlib.h>
-#include "./vp8i_dec.h"
-#include "./vp8li_dec.h"
-#include "./webpi_dec.h"
+#include "../dec/vp8i_dec.h"
+#include "../dec/vp8li_dec.h"
+#include "../dec/webpi_dec.h"
#include "../utils/utils.h"
#include "../webp/mux_types.h" // ALPHA_FLAG
@@ -421,7 +421,9 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
NULL, NULL, NULL, &has_animation,
NULL, headers);
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
- // TODO(jzern): full support of animation frames will require API additions.
+ // The WebPDemux API + libwebp can be used to decode individual
+ // uncomposited frames or the WebPAnimDecoder can be used to fully
+ // reconstruct them (see webp/demux.h).
if (has_animation) {
status = VP8_STATUS_UNSUPPORTED_FEATURE;
}
diff --git a/media/libwebp/dec/webpi_dec.h b/media/libwebp/dec/webpi_dec.h
index 696abc195..d0a045e70 100644
--- a/media/libwebp/dec/webpi_dec.h
+++ b/media/libwebp/dec/webpi_dec.h
@@ -11,15 +11,15 @@
//
// Author: somnath@google.com (Somnath Banerjee)
-#ifndef WEBP_DEC_WEBPI_H_
-#define WEBP_DEC_WEBPI_H_
+#ifndef WEBP_DEC_WEBPI_DEC_H_
+#define WEBP_DEC_WEBPI_DEC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "../utils/rescaler_utils.h"
-#include "./vp8_dec.h"
+#include "../dec/vp8_dec.h"
//------------------------------------------------------------------------------
// WebPDecParams: Decoding output parameters. Transient internal object.
@@ -130,4 +130,4 @@ int WebPAvoidSlowMemory(const WebPDecBuffer* const output,
} // extern "C"
#endif
-#endif /* WEBP_DEC_WEBPI_H_ */
+#endif /* WEBP_DEC_WEBPI_DEC_H_ */
diff --git a/media/libwebp/demux/demux.c b/media/libwebp/demux/demux.c
index 100eab8c0..aec2a0a2d 100644
--- a/media/libwebp/demux/demux.c
+++ b/media/libwebp/demux/demux.c
@@ -23,9 +23,9 @@
#include "../webp/demux.h"
#include "../webp/format_constants.h"
-#define DMUX_MAJ_VERSION 0
-#define DMUX_MIN_VERSION 3
-#define DMUX_REV_VERSION 2
+#define DMUX_MAJ_VERSION 1
+#define DMUX_MIN_VERSION 0
+#define DMUX_REV_VERSION 0
typedef struct {
size_t start_; // start location of the data
@@ -205,12 +205,14 @@ static void SetFrameInfo(size_t start_offset, size_t size,
frame->complete_ = complete;
}
-// Store image bearing chunks to 'frame'.
+// Store image bearing chunks to 'frame'. 'min_size' is an optional size
+// requirement, it may be zero.
static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
MemBuffer* const mem, Frame* const frame) {
int alpha_chunks = 0;
int image_chunks = 0;
- int done = (MemDataSize(mem) < min_size);
+ int done = (MemDataSize(mem) < CHUNK_HEADER_SIZE ||
+ MemDataSize(mem) < min_size);
ParseStatus status = PARSE_OK;
if (done) return PARSE_NEED_MORE_DATA;
@@ -401,9 +403,9 @@ static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
if (frame == NULL) return PARSE_ERROR;
- // For the single image case we allow parsing of a partial frame, but we need
- // at least CHUNK_HEADER_SIZE for parsing.
- status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
+ // For the single image case we allow parsing of a partial frame, so no
+ // minimum size is imposed here.
+ status = StoreFrame(1, 0, &dmux->mem_, frame);
if (status != PARSE_ERROR) {
const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
// Clear any alpha when the alpha flag is missing.
diff --git a/media/libwebp/dsp/alpha_processing.c b/media/libwebp/dsp/alpha_processing.c
index 4b60e092b..6ff1352ae 100644
--- a/media/libwebp/dsp/alpha_processing.c
+++ b/media/libwebp/dsp/alpha_processing.c
@@ -12,10 +12,13 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
-#include "./dsp.h"
+#include "../dsp/dsp.h"
// Tables can be faster on some platform but incur some extra binary size (~2k).
-// #define USE_TABLES_FOR_ALPHA_MULT
+#if !defined(USE_TABLES_FOR_ALPHA_MULT)
+#define USE_TABLES_FOR_ALPHA_MULT 0 // ALTERNATE_CODE
+#endif
+
// -----------------------------------------------------------------------------
@@ -29,7 +32,7 @@ static uint32_t Mult(uint8_t x, uint32_t mult) {
return v;
}
-#ifdef USE_TABLES_FOR_ALPHA_MULT
+#if (USE_TABLES_FOR_ALPHA_MULT == 1)
static const uint32_t kMultTables[2][256] = {
{ // (255u << MFIX) / alpha
@@ -132,9 +135,9 @@ static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
return inverse ? (255u << MFIX) / a : a * KINV_255;
}
-#endif // USE_TABLES_FOR_ALPHA_MULT
+#endif // USE_TABLES_FOR_ALPHA_MULT
-void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse) {
+void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse) {
int x;
for (x = 0; x < width; ++x) {
const uint32_t argb = ptr[x];
@@ -154,8 +157,8 @@ void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse) {
}
}
-void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
- int width, int inverse) {
+void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse) {
int x;
for (x = 0; x < width; ++x) {
const uint32_t a = alpha[x];
@@ -217,8 +220,9 @@ void WebPMultRows(uint8_t* ptr, int stride,
#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
#endif
-static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
- int w, int h, int stride) {
+#if !WEBP_NEON_OMIT_C_CODE
+static void ApplyAlphaMultiply_C(uint8_t* rgba, int alpha_first,
+ int w, int h, int stride) {
while (h-- > 0) {
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
@@ -235,6 +239,7 @@ static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
rgba += stride;
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
#undef MULTIPLIER
#undef PREMULTIPLY
@@ -254,9 +259,9 @@ static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
return (x * m) >> 16;
}
-static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
- int w, int h, int stride,
- int rg_byte_pos /* 0 or 1 */) {
+static WEBP_INLINE void ApplyAlphaMultiply4444_C(uint8_t* rgba4444,
+ int w, int h, int stride,
+ int rg_byte_pos /* 0 or 1 */) {
while (h-- > 0) {
int i;
for (i = 0; i < w; ++i) {
@@ -275,15 +280,16 @@ static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
}
#undef MULTIPLIER
-static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
- int w, int h, int stride) {
-#ifdef WEBP_SWAP_16BIT_CSP
- ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
+static void ApplyAlphaMultiply_16b_C(uint8_t* rgba4444,
+ int w, int h, int stride) {
+#if (WEBP_SWAP_16BIT_CSP == 1)
+ ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 1);
#else
- ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
+ ApplyAlphaMultiply4444_C(rgba4444, w, h, stride, 0);
#endif
}
+#if !WEBP_NEON_OMIT_C_CODE
static int DispatchAlpha_C(const uint8_t* alpha, int alpha_stride,
int width, int height,
uint8_t* dst, int dst_stride) {
@@ -338,6 +344,46 @@ static void ExtractGreen_C(const uint32_t* argb, uint8_t* alpha, int size) {
int i;
for (i = 0; i < size; ++i) alpha[i] = argb[i] >> 8;
}
+#endif // !WEBP_NEON_OMIT_C_CODE
+
+//------------------------------------------------------------------------------
+
+static int HasAlpha8b_C(const uint8_t* src, int length) {
+ while (length-- > 0) if (*src++ != 0xff) return 1;
+ return 0;
+}
+
+static int HasAlpha32b_C(const uint8_t* src, int length) {
+ int x;
+ for (x = 0; length-- > 0; x += 4) if (src[x] != 0xff) return 1;
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Simple channel manipulations.
+
+static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
+ return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
+}
+
+#ifdef WORDS_BIGENDIAN
+static void PackARGB_C(const uint8_t* a, const uint8_t* r, const uint8_t* g,
+ const uint8_t* b, int len, uint32_t* out) {
+ int i;
+ for (i = 0; i < len; ++i) {
+ out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
+ }
+}
+#endif
+
+static void PackRGB_C(const uint8_t* r, const uint8_t* g, const uint8_t* b,
+ int len, int step, uint32_t* out) {
+ int i, offset = 0;
+ for (i = 0; i < len; ++i) {
+ out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
+ offset += step;
+ }
+}
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
@@ -345,6 +391,15 @@ int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
void (*WebPExtractGreen)(const uint32_t* argb, uint8_t* alpha, int size);
+#ifdef WORDS_BIGENDIAN
+void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r, const uint8_t* g,
+ const uint8_t* b, int, uint32_t*);
+#endif
+void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
+ int len, int step, uint32_t* out);
+
+int (*WebPHasAlpha8b)(const uint8_t* src, int length);
+int (*WebPHasAlpha32b)(const uint8_t* src, int length);
//------------------------------------------------------------------------------
// Init function
@@ -354,21 +409,25 @@ extern void WebPInitAlphaProcessingSSE2(void);
extern void WebPInitAlphaProcessingSSE41(void);
extern void WebPInitAlphaProcessingNEON(void);
-static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
- (VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
- if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return;
-
- WebPMultARGBRow = WebPMultARGBRowC;
- WebPMultRow = WebPMultRowC;
- WebPApplyAlphaMultiply = ApplyAlphaMultiply;
- WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
+WEBP_DSP_INIT_FUNC(WebPInitAlphaProcessing) {
+ WebPMultARGBRow = WebPMultARGBRow_C;
+ WebPMultRow = WebPMultRow_C;
+ WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b_C;
+#ifdef WORDS_BIGENDIAN
+ WebPPackARGB = PackARGB_C;
+#endif
+ WebPPackRGB = PackRGB_C;
+#if !WEBP_NEON_OMIT_C_CODE
+ WebPApplyAlphaMultiply = ApplyAlphaMultiply_C;
WebPDispatchAlpha = DispatchAlpha_C;
WebPDispatchAlphaToGreen = DispatchAlphaToGreen_C;
WebPExtractAlpha = ExtractAlpha_C;
WebPExtractGreen = ExtractGreen_C;
+#endif
+
+ WebPHasAlpha8b = HasAlpha8b_C;
+ WebPHasAlpha32b = HasAlpha32b_C;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
@@ -382,16 +441,32 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
#endif
}
#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- WebPInitAlphaProcessingNEON();
- }
-#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
if (VP8GetCPUInfo(kMIPSdspR2)) {
WebPInitAlphaProcessingMIPSdspR2();
}
#endif
}
- alpha_processing_last_cpuinfo_used = VP8GetCPUInfo;
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ WebPInitAlphaProcessingNEON();
+ }
+#endif
+
+ assert(WebPMultARGBRow != NULL);
+ assert(WebPMultRow != NULL);
+ assert(WebPApplyAlphaMultiply != NULL);
+ assert(WebPApplyAlphaMultiply4444 != NULL);
+ assert(WebPDispatchAlpha != NULL);
+ assert(WebPDispatchAlphaToGreen != NULL);
+ assert(WebPExtractAlpha != NULL);
+ assert(WebPExtractGreen != NULL);
+#ifdef WORDS_BIGENDIAN
+ assert(WebPPackARGB != NULL);
+#endif
+ assert(WebPPackRGB != NULL);
+ assert(WebPHasAlpha8b != NULL);
+ assert(WebPHasAlpha32b != NULL);
}
diff --git a/media/libwebp/dsp/alpha_processing_sse2.c b/media/libwebp/dsp/alpha_processing_sse2.c
index 83dc559fa..9a3bc4485 100644
--- a/media/libwebp/dsp/alpha_processing_sse2.c
+++ b/media/libwebp/dsp/alpha_processing_sse2.c
@@ -11,16 +11,16 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE2)
#include <emmintrin.h>
//------------------------------------------------------------------------------
-static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint8_t* dst, int dst_stride) {
+static int DispatchAlpha_SSE2(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint8_t* dst, int dst_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@@ -72,9 +72,9 @@ static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
return (alpha_and != 0xff);
}
-static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
- int width, int height,
- uint32_t* dst, int dst_stride) {
+static void DispatchAlphaToGreen_SSE2(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint32_t* dst, int dst_stride) {
int i, j;
const __m128i zero = _mm_setzero_si128();
const int limit = width & ~15;
@@ -98,9 +98,9 @@ static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
}
}
-static int ExtractAlpha(const uint8_t* argb, int argb_stride,
- int width, int height,
- uint8_t* alpha, int alpha_stride) {
+static int ExtractAlpha_SSE2(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@@ -210,6 +210,61 @@ static void ApplyAlphaMultiply_SSE2(uint8_t* rgba, int alpha_first,
#undef MULTIPLIER
#undef PREMULTIPLY
+//------------------------------------------------------------------------------
+// Alpha detection
+
+static int HasAlpha8b_SSE2(const uint8_t* src, int length) {
+ const __m128i all_0xff = _mm_set1_epi8(0xff);
+ int i = 0;
+ for (; i + 16 <= length; i += 16) {
+ const __m128i v = _mm_loadu_si128((const __m128i*)(src + i));
+ const __m128i bits = _mm_cmpeq_epi8(v, all_0xff);
+ const int mask = _mm_movemask_epi8(bits);
+ if (mask != 0xffff) return 1;
+ }
+ for (; i < length; ++i) if (src[i] != 0xff) return 1;
+ return 0;
+}
+
+static int HasAlpha32b_SSE2(const uint8_t* src, int length) {
+ const __m128i alpha_mask = _mm_set1_epi32(0xff);
+ const __m128i all_0xff = _mm_set1_epi8(0xff);
+ int i = 0;
+ // We don't know if we can access the last 3 bytes after the last alpha
+ // value 'src[4 * length - 4]' (because we don't know if alpha is the first
+ // or the last byte of the quadruplet). Hence the '-3' protection below.
+ length = length * 4 - 3; // size in bytes
+ for (; i + 64 <= length; i += 64) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0));
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 16));
+ const __m128i a2 = _mm_loadu_si128((const __m128i*)(src + i + 32));
+ const __m128i a3 = _mm_loadu_si128((const __m128i*)(src + i + 48));
+ const __m128i b0 = _mm_and_si128(a0, alpha_mask);
+ const __m128i b1 = _mm_and_si128(a1, alpha_mask);
+ const __m128i b2 = _mm_and_si128(a2, alpha_mask);
+ const __m128i b3 = _mm_and_si128(a3, alpha_mask);
+ const __m128i c0 = _mm_packs_epi32(b0, b1);
+ const __m128i c1 = _mm_packs_epi32(b2, b3);
+ const __m128i d = _mm_packus_epi16(c0, c1);
+ const __m128i bits = _mm_cmpeq_epi8(d, all_0xff);
+ const int mask = _mm_movemask_epi8(bits);
+ if (mask != 0xffff) return 1;
+ }
+ for (; i + 32 <= length; i += 32) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)(src + i + 0));
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)(src + i + 16));
+ const __m128i b0 = _mm_and_si128(a0, alpha_mask);
+ const __m128i b1 = _mm_and_si128(a1, alpha_mask);
+ const __m128i c = _mm_packs_epi32(b0, b1);
+ const __m128i d = _mm_packus_epi16(c, c);
+ const __m128i bits = _mm_cmpeq_epi8(d, all_0xff);
+ const int mask = _mm_movemask_epi8(bits);
+ if (mask != 0xffff) return 1;
+ }
+ for (; i <= length; i += 4) if (src[i] != 0xff) return 1;
+ return 0;
+}
+
// -----------------------------------------------------------------------------
// Apply alpha value to rows
@@ -238,7 +293,7 @@ static void MultARGBRow_SSE2(uint32_t* const ptr, int width, int inverse) {
}
}
width -= x;
- if (width > 0) WebPMultARGBRowC(ptr + x, width, inverse);
+ if (width > 0) WebPMultARGBRow_C(ptr + x, width, inverse);
}
static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
@@ -261,7 +316,7 @@ static void MultRow_SSE2(uint8_t* const ptr, const uint8_t* const alpha,
}
}
width -= x;
- if (width > 0) WebPMultRowC(ptr + x, alpha + x, width, inverse);
+ if (width > 0) WebPMultRow_C(ptr + x, alpha + x, width, inverse);
}
//------------------------------------------------------------------------------
@@ -273,9 +328,12 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
WebPMultARGBRow = MultARGBRow_SSE2;
WebPMultRow = MultRow_SSE2;
WebPApplyAlphaMultiply = ApplyAlphaMultiply_SSE2;
- WebPDispatchAlpha = DispatchAlpha;
- WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
- WebPExtractAlpha = ExtractAlpha;
+ WebPDispatchAlpha = DispatchAlpha_SSE2;
+ WebPDispatchAlphaToGreen = DispatchAlphaToGreen_SSE2;
+ WebPExtractAlpha = ExtractAlpha_SSE2;
+
+ WebPHasAlpha8b = HasAlpha8b_SSE2;
+ WebPHasAlpha32b = HasAlpha32b_SSE2;
}
#else // !WEBP_USE_SSE2
diff --git a/media/libwebp/dsp/alpha_processing_sse41.c b/media/libwebp/dsp/alpha_processing_sse41.c
index 986fde94e..e33c1aba4 100644
--- a/media/libwebp/dsp/alpha_processing_sse41.c
+++ b/media/libwebp/dsp/alpha_processing_sse41.c
@@ -11,7 +11,7 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE41)
@@ -19,9 +19,9 @@
//------------------------------------------------------------------------------
-static int ExtractAlpha(const uint8_t* argb, int argb_stride,
- int width, int height,
- uint8_t* alpha, int alpha_stride) {
+static int ExtractAlpha_SSE41(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
// alpha_and stores an 'and' operation of all the alpha[] values. The final
// value is not 0xff if any of the alpha[] is not equal to 0xff.
uint32_t alpha_and = 0xff;
@@ -82,7 +82,7 @@ static int ExtractAlpha(const uint8_t* argb, int argb_stride,
extern void WebPInitAlphaProcessingSSE41(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE41(void) {
- WebPExtractAlpha = ExtractAlpha;
+ WebPExtractAlpha = ExtractAlpha_SSE41;
}
#else // !WEBP_USE_SSE41
diff --git a/media/libwebp/dsp/common_sse2.h b/media/libwebp/dsp/common_sse2.h
index 995d7cf4e..e9f1ebff4 100644
--- a/media/libwebp/dsp/common_sse2.h
+++ b/media/libwebp/dsp/common_sse2.h
@@ -128,9 +128,9 @@ static WEBP_INLINE void VP8Transpose_2_4x4_16b(
// Pack the planar buffers
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
-static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1,
- __m128i* const in2, __m128i* const in3,
- __m128i* const in4, __m128i* const in5) {
+static WEBP_INLINE void VP8PlanarTo24b_SSE2(
+ __m128i* const in0, __m128i* const in1, __m128i* const in2,
+ __m128i* const in3, __m128i* const in4, __m128i* const in5) {
// The input is 6 registers of sixteen 8b but for the sake of explanation,
// let's take 6 registers of four 8b values.
// To pack, we will keep taking one every two 8b integer and move it
@@ -159,10 +159,10 @@ static WEBP_INLINE void VP8PlanarTo24b(__m128i* const in0, __m128i* const in1,
// Convert four packed four-channel buffers like argbargbargbargb... into the
// split channels aaaaa ... rrrr ... gggg .... bbbbb ......
-static WEBP_INLINE void VP8L32bToPlanar(__m128i* const in0,
- __m128i* const in1,
- __m128i* const in2,
- __m128i* const in3) {
+static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0,
+ __m128i* const in1,
+ __m128i* const in2,
+ __m128i* const in3) {
// Column-wise transpose.
const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);
const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);
diff --git a/media/libwebp/dsp/common_sse41.h b/media/libwebp/dsp/common_sse41.h
new file mode 100644
index 000000000..2f173c024
--- /dev/null
+++ b/media/libwebp/dsp/common_sse41.h
@@ -0,0 +1,132 @@
+// Copyright 2016 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.
+// -----------------------------------------------------------------------------
+//
+// SSE4 code common to several files.
+//
+// Author: Vincent Rabaud (vrabaud@google.com)
+
+#ifndef WEBP_DSP_COMMON_SSE41_H_
+#define WEBP_DSP_COMMON_SSE41_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(WEBP_USE_SSE41)
+#include <smmintrin.h>
+
+//------------------------------------------------------------------------------
+// Channel mixing.
+// Shuffles the input buffer as A0 0 0 A1 0 0 A2 ...
+#define WEBP_SSE41_SHUFF(OUT, IN0, IN1) \
+ OUT##0 = _mm_shuffle_epi8(*IN0, shuff0); \
+ OUT##1 = _mm_shuffle_epi8(*IN0, shuff1); \
+ OUT##2 = _mm_shuffle_epi8(*IN0, shuff2); \
+ OUT##3 = _mm_shuffle_epi8(*IN1, shuff0); \
+ OUT##4 = _mm_shuffle_epi8(*IN1, shuff1); \
+ OUT##5 = _mm_shuffle_epi8(*IN1, shuff2);
+
+// Pack the planar buffers
+// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
+// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
+static WEBP_INLINE void VP8PlanarTo24b_SSE41(
+ __m128i* const in0, __m128i* const in1, __m128i* const in2,
+ __m128i* const in3, __m128i* const in4, __m128i* const in5) {
+ __m128i R0, R1, R2, R3, R4, R5;
+ __m128i G0, G1, G2, G3, G4, G5;
+ __m128i B0, B1, B2, B3, B4, B5;
+
+ // Process R.
+ {
+ const __m128i shuff0 = _mm_set_epi8(
+ 5, -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0);
+ const __m128i shuff1 = _mm_set_epi8(
+ -1, 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1);
+ const __m128i shuff2 = _mm_set_epi8(
+ -1, -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1);
+ WEBP_SSE41_SHUFF(R, in0, in1)
+ }
+
+ // Process G.
+ {
+ // Same as before, just shifted to the left by one and including the right
+ // padding.
+ const __m128i shuff0 = _mm_set_epi8(
+ -1, -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1);
+ const __m128i shuff1 = _mm_set_epi8(
+ 10, -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5);
+ const __m128i shuff2 = _mm_set_epi8(
+ -1, 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1);
+ WEBP_SSE41_SHUFF(G, in2, in3)
+ }
+
+ // Process B.
+ {
+ const __m128i shuff0 = _mm_set_epi8(
+ -1, 4, -1, -1, 3, -1, -1, 2, -1, -1, 1, -1, -1, 0, -1, -1);
+ const __m128i shuff1 = _mm_set_epi8(
+ -1, -1, 9, -1, -1, 8, -1, -1, 7, -1, -1, 6, -1, -1, 5, -1);
+ const __m128i shuff2 = _mm_set_epi8(
+ 15, -1, -1, 14, -1, -1, 13, -1, -1, 12, -1, -1, 11, -1, -1, 10);
+ WEBP_SSE41_SHUFF(B, in4, in5)
+ }
+
+ // OR the different channels.
+ {
+ const __m128i RG0 = _mm_or_si128(R0, G0);
+ const __m128i RG1 = _mm_or_si128(R1, G1);
+ const __m128i RG2 = _mm_or_si128(R2, G2);
+ const __m128i RG3 = _mm_or_si128(R3, G3);
+ const __m128i RG4 = _mm_or_si128(R4, G4);
+ const __m128i RG5 = _mm_or_si128(R5, G5);
+ *in0 = _mm_or_si128(RG0, B0);
+ *in1 = _mm_or_si128(RG1, B1);
+ *in2 = _mm_or_si128(RG2, B2);
+ *in3 = _mm_or_si128(RG3, B3);
+ *in4 = _mm_or_si128(RG4, B4);
+ *in5 = _mm_or_si128(RG5, B5);
+ }
+}
+
+#undef WEBP_SSE41_SHUFF
+
+// Convert four packed four-channel buffers like argbargbargbargb... into the
+// split channels aaaaa ... rrrr ... gggg .... bbbbb ......
+static WEBP_INLINE void VP8L32bToPlanar_SSE41(__m128i* const in0,
+ __m128i* const in1,
+ __m128i* const in2,
+ __m128i* const in3) {
+ // aaaarrrrggggbbbb
+ const __m128i shuff0 =
+ _mm_set_epi8(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0);
+ const __m128i A0 = _mm_shuffle_epi8(*in0, shuff0);
+ const __m128i A1 = _mm_shuffle_epi8(*in1, shuff0);
+ const __m128i A2 = _mm_shuffle_epi8(*in2, shuff0);
+ const __m128i A3 = _mm_shuffle_epi8(*in3, shuff0);
+ // A0A1R0R1
+ // G0G1B0B1
+ // A2A3R2R3
+ // G0G1B0B1
+ const __m128i B0 = _mm_unpacklo_epi32(A0, A1);
+ const __m128i B1 = _mm_unpackhi_epi32(A0, A1);
+ const __m128i B2 = _mm_unpacklo_epi32(A2, A3);
+ const __m128i B3 = _mm_unpackhi_epi32(A2, A3);
+ *in3 = _mm_unpacklo_epi64(B0, B2);
+ *in2 = _mm_unpackhi_epi64(B0, B2);
+ *in1 = _mm_unpacklo_epi64(B1, B3);
+ *in0 = _mm_unpackhi_epi64(B1, B3);
+}
+
+#endif // WEBP_USE_SSE41
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_DSP_COMMON_SSE41_H_
diff --git a/media/libwebp/dsp/dec.c b/media/libwebp/dsp/dec.c
index 007e985d8..a599d26bc 100644
--- a/media/libwebp/dsp/dec.c
+++ b/media/libwebp/dsp/dec.c
@@ -11,7 +11,9 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include <assert.h>
+
+#include "../dsp/dsp.h"
#include "../dec/vp8i_dec.h"
#include "../utils/utils.h"
@@ -25,7 +27,7 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
// Transforms (Paragraph 14.4)
#define STORE(x, y, v) \
- dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3))
+ dst[(x) + (y) * BPS] = clip_8b(dst[(x) + (y) * BPS] + ((v) >> 3))
#define STORE2(y, dc, d, c) do { \
const int DC = (dc); \
@@ -38,7 +40,8 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
#define MUL1(a) ((((a) * 20091) >> 16) + (a))
#define MUL2(a) (((a) * 35468) >> 16)
-static void TransformOne(const int16_t* in, uint8_t* dst) {
+#if !WEBP_NEON_OMIT_C_CODE
+static void TransformOne_C(const int16_t* in, uint8_t* dst) {
int C[4 * 4], *tmp;
int i;
tmp = C;
@@ -78,7 +81,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
}
// Simplified transform when only in[0], in[1] and in[4] are non-zero
-static void TransformAC3(const int16_t* in, uint8_t* dst) {
+static void TransformAC3_C(const int16_t* in, uint8_t* dst) {
const int a = in[0] + 4;
const int c4 = MUL2(in[4]);
const int d4 = MUL1(in[4]);
@@ -93,19 +96,21 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
#undef MUL2
#undef STORE2
-static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
- TransformOne(in, dst);
+static void TransformTwo_C(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne_C(in, dst);
if (do_two) {
- TransformOne(in + 16, dst + 4);
+ TransformOne_C(in + 16, dst + 4);
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void TransformUV(const int16_t* in, uint8_t* dst) {
+static void TransformUV_C(const int16_t* in, uint8_t* dst) {
VP8Transform(in + 0 * 16, dst, 1);
VP8Transform(in + 2 * 16, dst + 4 * BPS, 1);
}
-static void TransformDC(const int16_t* in, uint8_t* dst) {
+#if !WEBP_NEON_OMIT_C_CODE
+static void TransformDC_C(const int16_t* in, uint8_t* dst) {
const int DC = in[0] + 4;
int i, j;
for (j = 0; j < 4; ++j) {
@@ -114,8 +119,9 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
}
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void TransformDCUV(const int16_t* in, uint8_t* dst) {
+static void TransformDCUV_C(const int16_t* in, uint8_t* dst) {
if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst);
if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4);
if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS);
@@ -127,7 +133,8 @@ static void TransformDCUV(const int16_t* in, uint8_t* dst) {
//------------------------------------------------------------------------------
// Paragraph 14.3
-static void TransformWHT(const int16_t* in, int16_t* out) {
+#if !WEBP_NEON_OMIT_C_CODE
+static void TransformWHT_C(const int16_t* in, int16_t* out) {
int tmp[16];
int i;
for (i = 0; i < 4; ++i) {
@@ -153,6 +160,7 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
out += 64;
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
@@ -161,6 +169,7 @@ void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
#define DST(x, y) dst[(x) + (y) * BPS]
+#if !WEBP_NEON_OMIT_C_CODE
static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
const uint8_t* top = dst - BPS;
const uint8_t* const clip0 = VP8kclip1 - top[-1];
@@ -174,21 +183,21 @@ static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
dst += BPS;
}
}
-static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
-static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
-static void TM16(uint8_t* dst) { TrueMotion(dst, 16); }
+static void TM4_C(uint8_t* dst) { TrueMotion(dst, 4); }
+static void TM8uv_C(uint8_t* dst) { TrueMotion(dst, 8); }
+static void TM16_C(uint8_t* dst) { TrueMotion(dst, 16); }
//------------------------------------------------------------------------------
// 16x16
-static void VE16(uint8_t* dst) { // vertical
+static void VE16_C(uint8_t* dst) { // vertical
int j;
for (j = 0; j < 16; ++j) {
memcpy(dst + j * BPS, dst - BPS, 16);
}
}
-static void HE16(uint8_t* dst) { // horizontal
+static void HE16_C(uint8_t* dst) { // horizontal
int j;
for (j = 16; j > 0; --j) {
memset(dst, dst[-1], 16);
@@ -203,7 +212,7 @@ static WEBP_INLINE void Put16(int v, uint8_t* dst) {
}
}
-static void DC16(uint8_t* dst) { // DC
+static void DC16_C(uint8_t* dst) { // DC
int DC = 16;
int j;
for (j = 0; j < 16; ++j) {
@@ -212,7 +221,7 @@ static void DC16(uint8_t* dst) { // DC
Put16(DC >> 5, dst);
}
-static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
+static void DC16NoTop_C(uint8_t* dst) { // DC with top samples not available
int DC = 8;
int j;
for (j = 0; j < 16; ++j) {
@@ -221,7 +230,7 @@ static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
Put16(DC >> 4, dst);
}
-static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
+static void DC16NoLeft_C(uint8_t* dst) { // DC with left samples not available
int DC = 8;
int i;
for (i = 0; i < 16; ++i) {
@@ -230,9 +239,10 @@ static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
Put16(DC >> 4, dst);
}
-static void DC16NoTopLeft(uint8_t* dst) { // DC with no top and left samples
+static void DC16NoTopLeft_C(uint8_t* dst) { // DC with no top and left samples
Put16(0x80, dst);
}
+#endif // !WEBP_NEON_OMIT_C_CODE
VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
@@ -242,7 +252,8 @@ VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
#define AVG3(a, b, c) ((uint8_t)(((a) + 2 * (b) + (c) + 2) >> 2))
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
-static void VE4(uint8_t* dst) { // vertical
+#if !WEBP_NEON_OMIT_C_CODE
+static void VE4_C(uint8_t* dst) { // vertical
const uint8_t* top = dst - BPS;
const uint8_t vals[4] = {
AVG3(top[-1], top[0], top[1]),
@@ -255,8 +266,9 @@ static void VE4(uint8_t* dst) { // vertical
memcpy(dst + i * BPS, vals, sizeof(vals));
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void HE4(uint8_t* dst) { // horizontal
+static void HE4_C(uint8_t* dst) { // horizontal
const int A = dst[-1 - BPS];
const int B = dst[-1];
const int C = dst[-1 + BPS];
@@ -268,7 +280,8 @@ static void HE4(uint8_t* dst) { // horizontal
WebPUint32ToMem(dst + 3 * BPS, 0x01010101U * AVG3(D, E, E));
}
-static void DC4(uint8_t* dst) { // DC
+#if !WEBP_NEON_OMIT_C_CODE
+static void DC4_C(uint8_t* dst) { // DC
uint32_t dc = 4;
int i;
for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
@@ -276,7 +289,7 @@ static void DC4(uint8_t* dst) { // DC
for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4);
}
-static void RD4(uint8_t* dst) { // Down-right
+static void RD4_C(uint8_t* dst) { // Down-right
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -295,7 +308,7 @@ static void RD4(uint8_t* dst) { // Down-right
DST(3, 0) = AVG3(D, C, B);
}
-static void LD4(uint8_t* dst) { // Down-Left
+static void LD4_C(uint8_t* dst) { // Down-Left
const int A = dst[0 - BPS];
const int B = dst[1 - BPS];
const int C = dst[2 - BPS];
@@ -312,8 +325,9 @@ static void LD4(uint8_t* dst) { // Down-Left
DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
DST(3, 3) = AVG3(G, H, H);
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void VR4(uint8_t* dst) { // Vertical-Right
+static void VR4_C(uint8_t* dst) { // Vertical-Right
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -335,7 +349,7 @@ static void VR4(uint8_t* dst) { // Vertical-Right
DST(3, 1) = AVG3(B, C, D);
}
-static void VL4(uint8_t* dst) { // Vertical-Left
+static void VL4_C(uint8_t* dst) { // Vertical-Left
const int A = dst[0 - BPS];
const int B = dst[1 - BPS];
const int C = dst[2 - BPS];
@@ -357,7 +371,7 @@ static void VL4(uint8_t* dst) { // Vertical-Left
DST(3, 3) = AVG3(F, G, H);
}
-static void HU4(uint8_t* dst) { // Horizontal-Up
+static void HU4_C(uint8_t* dst) { // Horizontal-Up
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -372,7 +386,7 @@ static void HU4(uint8_t* dst) { // Horizontal-Up
DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
}
-static void HD4(uint8_t* dst) { // Horizontal-Down
+static void HD4_C(uint8_t* dst) { // Horizontal-Down
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -404,14 +418,15 @@ VP8PredFunc VP8PredLuma4[NUM_BMODES];
//------------------------------------------------------------------------------
// Chroma
-static void VE8uv(uint8_t* dst) { // vertical
+#if !WEBP_NEON_OMIT_C_CODE
+static void VE8uv_C(uint8_t* dst) { // vertical
int j;
for (j = 0; j < 8; ++j) {
memcpy(dst + j * BPS, dst - BPS, 8);
}
}
-static void HE8uv(uint8_t* dst) { // horizontal
+static void HE8uv_C(uint8_t* dst) { // horizontal
int j;
for (j = 0; j < 8; ++j) {
memset(dst, dst[-1], 8);
@@ -427,7 +442,7 @@ static WEBP_INLINE void Put8x8uv(uint8_t value, uint8_t* dst) {
}
}
-static void DC8uv(uint8_t* dst) { // DC
+static void DC8uv_C(uint8_t* dst) { // DC
int dc0 = 8;
int i;
for (i = 0; i < 8; ++i) {
@@ -436,7 +451,7 @@ static void DC8uv(uint8_t* dst) { // DC
Put8x8uv(dc0 >> 4, dst);
}
-static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
+static void DC8uvNoLeft_C(uint8_t* dst) { // DC with no left samples
int dc0 = 4;
int i;
for (i = 0; i < 8; ++i) {
@@ -445,7 +460,7 @@ static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
Put8x8uv(dc0 >> 3, dst);
}
-static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
+static void DC8uvNoTop_C(uint8_t* dst) { // DC with no top samples
int dc0 = 4;
int i;
for (i = 0; i < 8; ++i) {
@@ -454,17 +469,19 @@ static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
Put8x8uv(dc0 >> 3, dst);
}
-static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
+static void DC8uvNoTopLeft_C(uint8_t* dst) { // DC with nothing
Put8x8uv(0x80, dst);
}
+#endif // !WEBP_NEON_OMIT_C_CODE
VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
//------------------------------------------------------------------------------
// Edge filtering functions
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
// 4 pixels in, 2 pixels out
-static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
+static WEBP_INLINE void DoFilter2_C(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892]
const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15]
@@ -474,7 +491,7 @@ static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
}
// 4 pixels in, 4 pixels out
-static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
+static WEBP_INLINE void DoFilter4_C(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0);
const int a1 = VP8ksclip2[(a + 4) >> 3];
@@ -487,7 +504,7 @@ static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
}
// 6 pixels in, 6 pixels out
-static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
+static WEBP_INLINE void DoFilter6_C(uint8_t* p, int step) {
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
@@ -503,18 +520,22 @@ static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
p[ 2*step] = VP8kclip1[q2 - a3];
}
-static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
+static WEBP_INLINE int Hev(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
return (VP8kabs0[p1 - p0] > thresh) || (VP8kabs0[q1 - q0] > thresh);
}
+#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
-static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int t) {
+#if !WEBP_NEON_OMIT_C_CODE
+static WEBP_INLINE int NeedsFilter_C(const uint8_t* p, int step, int t) {
const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
return ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) <= t);
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static WEBP_INLINE int needs_filter2(const uint8_t* p,
- int step, int t, int it) {
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+static WEBP_INLINE int NeedsFilter2_C(const uint8_t* p,
+ int step, int t, int it) {
const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step];
const int p0 = p[-step], q0 = p[0];
const int q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
@@ -523,140 +544,159 @@ static WEBP_INLINE int needs_filter2(const uint8_t* p,
VP8kabs0[p1 - p0] <= it && VP8kabs0[q3 - q2] <= it &&
VP8kabs0[q2 - q1] <= it && VP8kabs0[q1 - q0] <= it;
}
+#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
//------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
-static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+#if !WEBP_NEON_OMIT_C_CODE
+static void SimpleVFilter16_C(uint8_t* p, int stride, int thresh) {
int i;
const int thresh2 = 2 * thresh + 1;
for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i, stride, thresh2)) {
- do_filter2(p + i, stride);
+ if (NeedsFilter_C(p + i, stride, thresh2)) {
+ DoFilter2_C(p + i, stride);
}
}
}
-static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16_C(uint8_t* p, int stride, int thresh) {
int i;
const int thresh2 = 2 * thresh + 1;
for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i * stride, 1, thresh2)) {
- do_filter2(p + i * stride, 1);
+ if (NeedsFilter_C(p + i * stride, 1, thresh2)) {
+ DoFilter2_C(p + i * stride, 1);
}
}
}
-static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16i_C(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4 * stride;
- SimpleVFilter16(p, stride, thresh);
+ SimpleVFilter16_C(p, stride, thresh);
}
}
-static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16i_C(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
- SimpleHFilter16(p, stride, thresh);
+ SimpleHFilter16_C(p, stride, thresh);
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
//------------------------------------------------------------------------------
// Complex In-loop filtering (Paragraph 15.3)
-static WEBP_INLINE void FilterLoop26(uint8_t* p,
- int hstride, int vstride, int size,
- int thresh, int ithresh, int hev_thresh) {
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+static WEBP_INLINE void FilterLoop26_C(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh,
+ int hev_thresh) {
const int thresh2 = 2 * thresh + 1;
while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh2, ithresh)) {
- if (hev(p, hstride, hev_thresh)) {
- do_filter2(p, hstride);
+ if (NeedsFilter2_C(p, hstride, thresh2, ithresh)) {
+ if (Hev(p, hstride, hev_thresh)) {
+ DoFilter2_C(p, hstride);
} else {
- do_filter6(p, hstride);
+ DoFilter6_C(p, hstride);
}
}
p += vstride;
}
}
-static WEBP_INLINE void FilterLoop24(uint8_t* p,
- int hstride, int vstride, int size,
- int thresh, int ithresh, int hev_thresh) {
+static WEBP_INLINE void FilterLoop24_C(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh,
+ int hev_thresh) {
const int thresh2 = 2 * thresh + 1;
while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh2, ithresh)) {
- if (hev(p, hstride, hev_thresh)) {
- do_filter2(p, hstride);
+ if (NeedsFilter2_C(p, hstride, thresh2, ithresh)) {
+ if (Hev(p, hstride, hev_thresh)) {
+ DoFilter2_C(p, hstride);
} else {
- do_filter4(p, hstride);
+ DoFilter4_C(p, hstride);
}
}
p += vstride;
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+#if !WEBP_NEON_OMIT_C_CODE
// on macroblock edges
-static void VFilter16(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+static void VFilter16_C(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26_C(p, stride, 1, 16, thresh, ithresh, hev_thresh);
}
-static void HFilter16(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+static void HFilter16_C(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26_C(p, 1, stride, 16, thresh, ithresh, hev_thresh);
}
// on three inner edges
-static void VFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16i_C(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4 * stride;
- FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ FilterLoop24_C(p, stride, 1, 16, thresh, ithresh, hev_thresh);
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void HFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+static void HFilter16i_C(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
- FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ FilterLoop24_C(p, 1, stride, 16, thresh, ithresh, hev_thresh);
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+#if !WEBP_NEON_OMIT_C_CODE
// 8-pixels wide variant, for chroma filtering
-static void VFilter8(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
- FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
+static void VFilter8_C(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26_C(u, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26_C(v, stride, 1, 8, thresh, ithresh, hev_thresh);
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void HFilter8(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
- FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+static void HFilter8_C(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26_C(u, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26_C(v, 1, stride, 8, thresh, ithresh, hev_thresh);
}
+#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
-static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
- FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+#if !WEBP_NEON_OMIT_C_CODE
+static void VFilter8i_C(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24_C(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24_C(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
- FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+static void HFilter8i_C(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24_C(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24_C(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
}
+#endif // !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
//------------------------------------------------------------------------------
-static void DitherCombine8x8(const uint8_t* dither, uint8_t* dst,
- int dst_stride) {
+static void DitherCombine8x8_C(const uint8_t* dither, uint8_t* dst,
+ int dst_stride) {
int i, j;
for (j = 0; j < 8; ++j) {
for (i = 0; i < 8; ++i) {
@@ -701,62 +741,69 @@ extern void VP8DspInitMIPS32(void);
extern void VP8DspInitMIPSdspR2(void);
extern void VP8DspInitMSA(void);
-static volatile VP8CPUInfo dec_last_cpuinfo_used =
- (VP8CPUInfo)&dec_last_cpuinfo_used;
+WEBP_DSP_INIT_FUNC(VP8DspInit) {
+ VP8InitClipTables();
-WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
- if (dec_last_cpuinfo_used == VP8GetCPUInfo) return;
+#if !WEBP_NEON_OMIT_C_CODE
+ VP8TransformWHT = TransformWHT_C;
+ VP8Transform = TransformTwo_C;
+ VP8TransformDC = TransformDC_C;
+ VP8TransformAC3 = TransformAC3_C;
+#endif
+ VP8TransformUV = TransformUV_C;
+ VP8TransformDCUV = TransformDCUV_C;
+
+#if !WEBP_NEON_OMIT_C_CODE
+ VP8VFilter16 = VFilter16_C;
+ VP8VFilter16i = VFilter16i_C;
+ VP8HFilter16 = HFilter16_C;
+ VP8VFilter8 = VFilter8_C;
+ VP8VFilter8i = VFilter8i_C;
+ VP8SimpleVFilter16 = SimpleVFilter16_C;
+ VP8SimpleHFilter16 = SimpleHFilter16_C;
+ VP8SimpleVFilter16i = SimpleVFilter16i_C;
+ VP8SimpleHFilter16i = SimpleHFilter16i_C;
+#endif
- VP8InitClipTables();
+#if !WEBP_NEON_OMIT_C_CODE || WEBP_NEON_WORK_AROUND_GCC
+ VP8HFilter16i = HFilter16i_C;
+ VP8HFilter8 = HFilter8_C;
+ VP8HFilter8i = HFilter8i_C;
+#endif
+
+#if !WEBP_NEON_OMIT_C_CODE
+ VP8PredLuma4[0] = DC4_C;
+ VP8PredLuma4[1] = TM4_C;
+ VP8PredLuma4[2] = VE4_C;
+ VP8PredLuma4[4] = RD4_C;
+ VP8PredLuma4[6] = LD4_C;
+#endif
+
+ VP8PredLuma4[3] = HE4_C;
+ VP8PredLuma4[5] = VR4_C;
+ VP8PredLuma4[7] = VL4_C;
+ VP8PredLuma4[8] = HD4_C;
+ VP8PredLuma4[9] = HU4_C;
+
+#if !WEBP_NEON_OMIT_C_CODE
+ VP8PredLuma16[0] = DC16_C;
+ VP8PredLuma16[1] = TM16_C;
+ VP8PredLuma16[2] = VE16_C;
+ VP8PredLuma16[3] = HE16_C;
+ VP8PredLuma16[4] = DC16NoTop_C;
+ VP8PredLuma16[5] = DC16NoLeft_C;
+ VP8PredLuma16[6] = DC16NoTopLeft_C;
+
+ VP8PredChroma8[0] = DC8uv_C;
+ VP8PredChroma8[1] = TM8uv_C;
+ VP8PredChroma8[2] = VE8uv_C;
+ VP8PredChroma8[3] = HE8uv_C;
+ VP8PredChroma8[4] = DC8uvNoTop_C;
+ VP8PredChroma8[5] = DC8uvNoLeft_C;
+ VP8PredChroma8[6] = DC8uvNoTopLeft_C;
+#endif
- VP8TransformWHT = TransformWHT;
- VP8Transform = TransformTwo;
- VP8TransformUV = TransformUV;
- VP8TransformDC = TransformDC;
- VP8TransformDCUV = TransformDCUV;
- VP8TransformAC3 = TransformAC3;
-
- VP8VFilter16 = VFilter16;
- VP8HFilter16 = HFilter16;
- VP8VFilter8 = VFilter8;
- VP8HFilter8 = HFilter8;
- VP8VFilter16i = VFilter16i;
- VP8HFilter16i = HFilter16i;
- VP8VFilter8i = VFilter8i;
- VP8HFilter8i = HFilter8i;
- VP8SimpleVFilter16 = SimpleVFilter16;
- VP8SimpleHFilter16 = SimpleHFilter16;
- VP8SimpleVFilter16i = SimpleVFilter16i;
- VP8SimpleHFilter16i = SimpleHFilter16i;
-
- VP8PredLuma4[0] = DC4;
- VP8PredLuma4[1] = TM4;
- VP8PredLuma4[2] = VE4;
- VP8PredLuma4[3] = HE4;
- VP8PredLuma4[4] = RD4;
- VP8PredLuma4[5] = VR4;
- VP8PredLuma4[6] = LD4;
- VP8PredLuma4[7] = VL4;
- VP8PredLuma4[8] = HD4;
- VP8PredLuma4[9] = HU4;
-
- VP8PredLuma16[0] = DC16;
- VP8PredLuma16[1] = TM16;
- VP8PredLuma16[2] = VE16;
- VP8PredLuma16[3] = HE16;
- VP8PredLuma16[4] = DC16NoTop;
- VP8PredLuma16[5] = DC16NoLeft;
- VP8PredLuma16[6] = DC16NoTopLeft;
-
- VP8PredChroma8[0] = DC8uv;
- VP8PredChroma8[1] = TM8uv;
- VP8PredChroma8[2] = VE8uv;
- VP8PredChroma8[3] = HE8uv;
- VP8PredChroma8[4] = DC8uvNoTop;
- VP8PredChroma8[5] = DC8uvNoLeft;
- VP8PredChroma8[6] = DC8uvNoTopLeft;
-
- VP8DitherCombine8x8 = DitherCombine8x8;
+ VP8DitherCombine8x8 = DitherCombine8x8_C;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
@@ -770,11 +817,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
#endif
}
#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- VP8DspInitNEON();
- }
-#endif
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
VP8DspInitMIPS32();
@@ -791,5 +833,55 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
}
#endif
}
- dec_last_cpuinfo_used = VP8GetCPUInfo;
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ VP8DspInitNEON();
+ }
+#endif
+
+ assert(VP8TransformWHT != NULL);
+ assert(VP8Transform != NULL);
+ assert(VP8TransformDC != NULL);
+ assert(VP8TransformAC3 != NULL);
+ assert(VP8TransformUV != NULL);
+ assert(VP8TransformDCUV != NULL);
+ assert(VP8VFilter16 != NULL);
+ assert(VP8HFilter16 != NULL);
+ assert(VP8VFilter8 != NULL);
+ assert(VP8HFilter8 != NULL);
+ assert(VP8VFilter16i != NULL);
+ assert(VP8HFilter16i != NULL);
+ assert(VP8VFilter8i != NULL);
+ assert(VP8HFilter8i != NULL);
+ assert(VP8SimpleVFilter16 != NULL);
+ assert(VP8SimpleHFilter16 != NULL);
+ assert(VP8SimpleVFilter16i != NULL);
+ assert(VP8SimpleHFilter16i != NULL);
+ assert(VP8PredLuma4[0] != NULL);
+ assert(VP8PredLuma4[1] != NULL);
+ assert(VP8PredLuma4[2] != NULL);
+ assert(VP8PredLuma4[3] != NULL);
+ assert(VP8PredLuma4[4] != NULL);
+ assert(VP8PredLuma4[5] != NULL);
+ assert(VP8PredLuma4[6] != NULL);
+ assert(VP8PredLuma4[7] != NULL);
+ assert(VP8PredLuma4[8] != NULL);
+ assert(VP8PredLuma4[9] != NULL);
+ assert(VP8PredLuma16[0] != NULL);
+ assert(VP8PredLuma16[1] != NULL);
+ assert(VP8PredLuma16[2] != NULL);
+ assert(VP8PredLuma16[3] != NULL);
+ assert(VP8PredLuma16[4] != NULL);
+ assert(VP8PredLuma16[5] != NULL);
+ assert(VP8PredLuma16[6] != NULL);
+ assert(VP8PredChroma8[0] != NULL);
+ assert(VP8PredChroma8[1] != NULL);
+ assert(VP8PredChroma8[2] != NULL);
+ assert(VP8PredChroma8[3] != NULL);
+ assert(VP8PredChroma8[4] != NULL);
+ assert(VP8PredChroma8[5] != NULL);
+ assert(VP8PredChroma8[6] != NULL);
+ assert(VP8DitherCombine8x8 != NULL);
}
diff --git a/media/libwebp/dsp/dec_clip_tables.c b/media/libwebp/dsp/dec_clip_tables.c
index 74ba34c0b..9c86011d2 100644
--- a/media/libwebp/dsp/dec_clip_tables.c
+++ b/media/libwebp/dsp/dec_clip_tables.c
@@ -11,11 +11,14 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
-#define USE_STATIC_TABLES // undefine to have run-time table initialization
+// define to 0 to have run-time table initialization
+#if !defined(USE_STATIC_TABLES)
+#define USE_STATIC_TABLES 1 // ALTERNATE_CODE
+#endif
-#ifdef USE_STATIC_TABLES
+#if (USE_STATIC_TABLES == 1)
static const uint8_t abs0[255 + 255 + 1] = {
0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4,
@@ -337,7 +340,7 @@ static uint8_t clip1[255 + 511 + 1];
// and make sure it's set to true _last_ (so as to be thread-safe)
static volatile int tables_ok = 0;
-#endif
+#endif // USE_STATIC_TABLES
const int8_t* const VP8ksclip1 = (const int8_t*)&sclip1[1020];
const int8_t* const VP8ksclip2 = (const int8_t*)&sclip2[112];
@@ -345,7 +348,7 @@ const uint8_t* const VP8kclip1 = &clip1[255];
const uint8_t* const VP8kabs0 = &abs0[255];
WEBP_TSAN_IGNORE_FUNCTION void VP8InitClipTables(void) {
-#if !defined(USE_STATIC_TABLES)
+#if (USE_STATIC_TABLES == 0)
int i;
if (!tables_ok) {
for (i = -255; i <= 255; ++i) {
diff --git a/media/libwebp/dsp/dec_neon.c b/media/libwebp/dsp/dec_neon.c
index 34796cf4a..e8341327e 100644
--- a/media/libwebp/dsp/dec_neon.c
+++ b/media/libwebp/dsp/dec_neon.c
@@ -12,43 +12,23 @@
// Authors: Somnath Banerjee (somnath@google.com)
// Johann Koenig (johannkoenig@google.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_NEON)
-#include "./neon.h"
+#include "../dsp/neon.h"
#include "../dec/vp8i_dec.h"
//------------------------------------------------------------------------------
// NxM Loading functions
-// Load/Store vertical edge
-#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
- "vld4.8 {" #c1 "[0]," #c2 "[0]," #c3 "[0]," #c4 "[0]}," #b1 "," #stride "\n" \
- "vld4.8 {" #c1 "[1]," #c2 "[1]," #c3 "[1]," #c4 "[1]}," #b2 "," #stride "\n" \
- "vld4.8 {" #c1 "[2]," #c2 "[2]," #c3 "[2]," #c4 "[2]}," #b1 "," #stride "\n" \
- "vld4.8 {" #c1 "[3]," #c2 "[3]," #c3 "[3]," #c4 "[3]}," #b2 "," #stride "\n" \
- "vld4.8 {" #c1 "[4]," #c2 "[4]," #c3 "[4]," #c4 "[4]}," #b1 "," #stride "\n" \
- "vld4.8 {" #c1 "[5]," #c2 "[5]," #c3 "[5]," #c4 "[5]}," #b2 "," #stride "\n" \
- "vld4.8 {" #c1 "[6]," #c2 "[6]," #c3 "[6]," #c4 "[6]}," #b1 "," #stride "\n" \
- "vld4.8 {" #c1 "[7]," #c2 "[7]," #c3 "[7]," #c4 "[7]}," #b2 "," #stride "\n"
-
-#define STORE8x2(c1, c2, p, stride) \
- "vst2.8 {" #c1 "[0], " #c2 "[0]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[1], " #c2 "[1]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[2], " #c2 "[2]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[3], " #c2 "[3]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[4], " #c2 "[4]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[5], " #c2 "[5]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[6], " #c2 "[6]}," #p "," #stride " \n" \
- "vst2.8 {" #c1 "[7], " #c2 "[7]}," #p "," #stride " \n"
-
#if !defined(WORK_AROUND_GCC)
// This intrinsics version makes gcc-4.6.3 crash during Load4x??() compilation
// (register alloc, probably). The variants somewhat mitigate the problem, but
// not quite. HFilter16i() remains problematic.
-static WEBP_INLINE uint8x8x4_t Load4x8(const uint8_t* const src, int stride) {
+static WEBP_INLINE uint8x8x4_t Load4x8_NEON(const uint8_t* const src,
+ int stride) {
const uint8x8_t zero = vdup_n_u8(0);
uint8x8x4_t out;
INIT_VECTOR4(out, zero, zero, zero, zero);
@@ -63,13 +43,15 @@ static WEBP_INLINE uint8x8x4_t Load4x8(const uint8_t* const src, int stride) {
return out;
}
-static WEBP_INLINE void Load4x16(const uint8_t* const src, int stride,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1) {
+static WEBP_INLINE void Load4x16_NEON(const uint8_t* const src, int stride,
+ uint8x16_t* const p1,
+ uint8x16_t* const p0,
+ uint8x16_t* const q0,
+ uint8x16_t* const q1) {
// row0 = p1[0..7]|p0[0..7]|q0[0..7]|q1[0..7]
// row8 = p1[8..15]|p0[8..15]|q0[8..15]|q1[8..15]
- const uint8x8x4_t row0 = Load4x8(src - 2 + 0 * stride, stride);
- const uint8x8x4_t row8 = Load4x8(src - 2 + 8 * stride, stride);
+ const uint8x8x4_t row0 = Load4x8_NEON(src - 2 + 0 * stride, stride);
+ const uint8x8x4_t row8 = Load4x8_NEON(src - 2 + 8 * stride, stride);
*p1 = vcombine_u8(row0.val[0], row8.val[0]);
*p0 = vcombine_u8(row0.val[1], row8.val[1]);
*q0 = vcombine_u8(row0.val[2], row8.val[2]);
@@ -83,9 +65,11 @@ static WEBP_INLINE void Load4x16(const uint8_t* const src, int stride,
src += stride; \
} while (0)
-static WEBP_INLINE void Load4x16(const uint8_t* src, int stride,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1) {
+static WEBP_INLINE void Load4x16_NEON(const uint8_t* src, int stride,
+ uint8x16_t* const p1,
+ uint8x16_t* const p0,
+ uint8x16_t* const q0,
+ uint8x16_t* const q1) {
const uint32x4_t zero = vdupq_n_u32(0);
uint32x4x4_t in;
INIT_VECTOR4(in, zero, zero, zero, zero);
@@ -126,40 +110,40 @@ static WEBP_INLINE void Load4x16(const uint8_t* src, int stride,
#endif // !WORK_AROUND_GCC
-static WEBP_INLINE void Load8x16(const uint8_t* const src, int stride,
- uint8x16_t* const p3, uint8x16_t* const p2,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1,
- uint8x16_t* const q2, uint8x16_t* const q3) {
- Load4x16(src - 2, stride, p3, p2, p1, p0);
- Load4x16(src + 2, stride, q0, q1, q2, q3);
+static WEBP_INLINE void Load8x16_NEON(
+ const uint8_t* const src, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1,
+ uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ Load4x16_NEON(src - 2, stride, p3, p2, p1, p0);
+ Load4x16_NEON(src + 2, stride, q0, q1, q2, q3);
}
-static WEBP_INLINE void Load16x4(const uint8_t* const src, int stride,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1) {
+static WEBP_INLINE void Load16x4_NEON(const uint8_t* const src, int stride,
+ uint8x16_t* const p1,
+ uint8x16_t* const p0,
+ uint8x16_t* const q0,
+ uint8x16_t* const q1) {
*p1 = vld1q_u8(src - 2 * stride);
*p0 = vld1q_u8(src - 1 * stride);
*q0 = vld1q_u8(src + 0 * stride);
*q1 = vld1q_u8(src + 1 * stride);
}
-static WEBP_INLINE void Load16x8(const uint8_t* const src, int stride,
- uint8x16_t* const p3, uint8x16_t* const p2,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1,
- uint8x16_t* const q2, uint8x16_t* const q3) {
- Load16x4(src - 2 * stride, stride, p3, p2, p1, p0);
- Load16x4(src + 2 * stride, stride, q0, q1, q2, q3);
+static WEBP_INLINE void Load16x8_NEON(
+ const uint8_t* const src, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1,
+ uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ Load16x4_NEON(src - 2 * stride, stride, p3, p2, p1, p0);
+ Load16x4_NEON(src + 2 * stride, stride, q0, q1, q2, q3);
}
-static WEBP_INLINE void Load8x8x2(const uint8_t* const u,
- const uint8_t* const v,
- int stride,
- uint8x16_t* const p3, uint8x16_t* const p2,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1,
- uint8x16_t* const q2, uint8x16_t* const q3) {
+static WEBP_INLINE void Load8x8x2_NEON(
+ const uint8_t* const u, const uint8_t* const v, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1,
+ uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
// We pack the 8x8 u-samples in the lower half of the uint8x16_t destination
// and the v-samples on the higher half.
*p3 = vcombine_u8(vld1_u8(u - 4 * stride), vld1_u8(v - 4 * stride));
@@ -177,13 +161,11 @@ static WEBP_INLINE void Load8x8x2(const uint8_t* const u,
#define LOAD_UV_8(ROW) \
vcombine_u8(vld1_u8(u - 4 + (ROW) * stride), vld1_u8(v - 4 + (ROW) * stride))
-static WEBP_INLINE void Load8x8x2T(const uint8_t* const u,
- const uint8_t* const v,
- int stride,
- uint8x16_t* const p3, uint8x16_t* const p2,
- uint8x16_t* const p1, uint8x16_t* const p0,
- uint8x16_t* const q0, uint8x16_t* const q1,
- uint8x16_t* const q2, uint8x16_t* const q3) {
+static WEBP_INLINE void Load8x8x2T_NEON(
+ const uint8_t* const u, const uint8_t* const v, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2, uint8x16_t* const p1,
+ uint8x16_t* const p0, uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
// We pack the 8x8 u-samples in the lower half of the uint8x16_t destination
// and the v-samples on the higher half.
const uint8x16_t row0 = LOAD_UV_8(0);
@@ -238,8 +220,8 @@ static WEBP_INLINE void Load8x8x2T(const uint8_t* const u,
#endif // !WORK_AROUND_GCC
-static WEBP_INLINE void Store2x8(const uint8x8x2_t v,
- uint8_t* const dst, int stride) {
+static WEBP_INLINE void Store2x8_NEON(const uint8x8x2_t v,
+ uint8_t* const dst, int stride) {
vst2_lane_u8(dst + 0 * stride, v, 0);
vst2_lane_u8(dst + 1 * stride, v, 1);
vst2_lane_u8(dst + 2 * stride, v, 2);
@@ -250,20 +232,20 @@ static WEBP_INLINE void Store2x8(const uint8x8x2_t v,
vst2_lane_u8(dst + 7 * stride, v, 7);
}
-static WEBP_INLINE void Store2x16(const uint8x16_t p0, const uint8x16_t q0,
- uint8_t* const dst, int stride) {
+static WEBP_INLINE void Store2x16_NEON(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const dst, int stride) {
uint8x8x2_t lo, hi;
lo.val[0] = vget_low_u8(p0);
lo.val[1] = vget_low_u8(q0);
hi.val[0] = vget_high_u8(p0);
hi.val[1] = vget_high_u8(q0);
- Store2x8(lo, dst - 1 + 0 * stride, stride);
- Store2x8(hi, dst - 1 + 8 * stride, stride);
+ Store2x8_NEON(lo, dst - 1 + 0 * stride, stride);
+ Store2x8_NEON(hi, dst - 1 + 8 * stride, stride);
}
#if !defined(WORK_AROUND_GCC)
-static WEBP_INLINE void Store4x8(const uint8x8x4_t v,
- uint8_t* const dst, int stride) {
+static WEBP_INLINE void Store4x8_NEON(const uint8x8x4_t v,
+ uint8_t* const dst, int stride) {
vst4_lane_u8(dst + 0 * stride, v, 0);
vst4_lane_u8(dst + 1 * stride, v, 1);
vst4_lane_u8(dst + 2 * stride, v, 2);
@@ -274,9 +256,9 @@ static WEBP_INLINE void Store4x8(const uint8x8x4_t v,
vst4_lane_u8(dst + 7 * stride, v, 7);
}
-static WEBP_INLINE void Store4x16(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- uint8_t* const dst, int stride) {
+static WEBP_INLINE void Store4x16_NEON(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const dst, int stride) {
uint8x8x4_t lo, hi;
INIT_VECTOR4(lo,
vget_low_u8(p1), vget_low_u8(p0),
@@ -284,27 +266,28 @@ static WEBP_INLINE void Store4x16(const uint8x16_t p1, const uint8x16_t p0,
INIT_VECTOR4(hi,
vget_high_u8(p1), vget_high_u8(p0),
vget_high_u8(q0), vget_high_u8(q1));
- Store4x8(lo, dst - 2 + 0 * stride, stride);
- Store4x8(hi, dst - 2 + 8 * stride, stride);
+ Store4x8_NEON(lo, dst - 2 + 0 * stride, stride);
+ Store4x8_NEON(hi, dst - 2 + 8 * stride, stride);
}
#endif // !WORK_AROUND_GCC
-static WEBP_INLINE void Store16x2(const uint8x16_t p0, const uint8x16_t q0,
- uint8_t* const dst, int stride) {
+static WEBP_INLINE void Store16x2_NEON(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const dst, int stride) {
vst1q_u8(dst - stride, p0);
vst1q_u8(dst, q0);
}
-static WEBP_INLINE void Store16x4(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- uint8_t* const dst, int stride) {
- Store16x2(p1, p0, dst - stride, stride);
- Store16x2(q0, q1, dst + stride, stride);
+static WEBP_INLINE void Store16x4_NEON(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const dst, int stride) {
+ Store16x2_NEON(p1, p0, dst - stride, stride);
+ Store16x2_NEON(q0, q1, dst + stride, stride);
}
-static WEBP_INLINE void Store8x2x2(const uint8x16_t p0, const uint8x16_t q0,
- uint8_t* const u, uint8_t* const v,
- int stride) {
+static WEBP_INLINE void Store8x2x2_NEON(const uint8x16_t p0,
+ const uint8x16_t q0,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
// p0 and q0 contain the u+v samples packed in low/high halves.
vst1_u8(u - stride, vget_low_u8(p0));
vst1_u8(u, vget_low_u8(q0));
@@ -312,13 +295,15 @@ static WEBP_INLINE void Store8x2x2(const uint8x16_t p0, const uint8x16_t q0,
vst1_u8(v, vget_high_u8(q0));
}
-static WEBP_INLINE void Store8x4x2(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- uint8_t* const u, uint8_t* const v,
- int stride) {
+static WEBP_INLINE void Store8x4x2_NEON(const uint8x16_t p1,
+ const uint8x16_t p0,
+ const uint8x16_t q0,
+ const uint8x16_t q1,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
// The p1...q1 registers contain the u+v samples packed in low/high halves.
- Store8x2x2(p1, p0, u - stride, v - stride, stride);
- Store8x2x2(q0, q1, u + stride, v + stride, stride);
+ Store8x2x2_NEON(p1, p0, u - stride, v - stride, stride);
+ Store8x2x2_NEON(q0, q1, u + stride, v + stride, stride);
}
#if !defined(WORK_AROUND_GCC)
@@ -329,11 +314,10 @@ static WEBP_INLINE void Store8x4x2(const uint8x16_t p1, const uint8x16_t p0,
(DST) += stride; \
} while (0)
-static WEBP_INLINE void Store6x8x2(const uint8x16_t p2, const uint8x16_t p1,
- const uint8x16_t p0, const uint8x16_t q0,
- const uint8x16_t q1, const uint8x16_t q2,
- uint8_t* u, uint8_t* v,
- int stride) {
+static WEBP_INLINE void Store6x8x2_NEON(
+ const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2,
+ uint8_t* u, uint8_t* v, int stride) {
uint8x8x3_t u0, u1, v0, v1;
INIT_VECTOR3(u0, vget_low_u8(p2), vget_low_u8(p1), vget_low_u8(p0));
INIT_VECTOR3(u1, vget_low_u8(q0), vget_low_u8(q1), vget_low_u8(q2));
@@ -358,10 +342,12 @@ static WEBP_INLINE void Store6x8x2(const uint8x16_t p2, const uint8x16_t p1,
}
#undef STORE6_LANE
-static WEBP_INLINE void Store4x8x2(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- uint8_t* const u, uint8_t* const v,
- int stride) {
+static WEBP_INLINE void Store4x8x2_NEON(const uint8x16_t p1,
+ const uint8x16_t p0,
+ const uint8x16_t q0,
+ const uint8x16_t q1,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
uint8x8x4_t u0, v0;
INIT_VECTOR4(u0,
vget_low_u8(p1), vget_low_u8(p0),
@@ -390,15 +376,15 @@ static WEBP_INLINE void Store4x8x2(const uint8x16_t p1, const uint8x16_t p0,
#endif // !WORK_AROUND_GCC
// Zero extend 'v' to an int16x8_t.
-static WEBP_INLINE int16x8_t ConvertU8ToS16(uint8x8_t v) {
+static WEBP_INLINE int16x8_t ConvertU8ToS16_NEON(uint8x8_t v) {
return vreinterpretq_s16_u16(vmovl_u8(v));
}
// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result
// to the corresponding rows of 'dst'.
-static WEBP_INLINE void SaturateAndStore4x4(uint8_t* const dst,
- const int16x8_t dst01,
- const int16x8_t dst23) {
+static WEBP_INLINE void SaturateAndStore4x4_NEON(uint8_t* const dst,
+ const int16x8_t dst01,
+ const int16x8_t dst23) {
// Unsigned saturate to 8b.
const uint8x8_t dst01_u8 = vqmovun_s16(dst01);
const uint8x8_t dst23_u8 = vqmovun_s16(dst23);
@@ -410,8 +396,9 @@ static WEBP_INLINE void SaturateAndStore4x4(uint8_t* const dst,
vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1);
}
-static WEBP_INLINE void Add4x4(const int16x8_t row01, const int16x8_t row23,
- uint8_t* const dst) {
+static WEBP_INLINE void Add4x4_NEON(const int16x8_t row01,
+ const int16x8_t row23,
+ uint8_t* const dst) {
uint32x2_t dst01 = vdup_n_u32(0);
uint32x2_t dst23 = vdup_n_u32(0);
@@ -423,23 +410,23 @@ static WEBP_INLINE void Add4x4(const int16x8_t row01, const int16x8_t row23,
{
// Convert to 16b.
- const int16x8_t dst01_s16 = ConvertU8ToS16(vreinterpret_u8_u32(dst01));
- const int16x8_t dst23_s16 = ConvertU8ToS16(vreinterpret_u8_u32(dst23));
+ const int16x8_t dst01_s16 = ConvertU8ToS16_NEON(vreinterpret_u8_u32(dst01));
+ const int16x8_t dst23_s16 = ConvertU8ToS16_NEON(vreinterpret_u8_u32(dst23));
// Descale with rounding.
const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3);
const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3);
// Add the inverse transform.
- SaturateAndStore4x4(dst, out01, out23);
+ SaturateAndStore4x4_NEON(dst, out01, out23);
}
}
//-----------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
-static uint8x16_t NeedsFilter(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- int thresh) {
+static uint8x16_t NeedsFilter_NEON(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ int thresh) {
const uint8x16_t thresh_v = vdupq_n_u8((uint8_t)thresh);
const uint8x16_t a_p0_q0 = vabdq_u8(p0, q0); // abs(p0-q0)
const uint8x16_t a_p1_q1 = vabdq_u8(p1, q1); // abs(p1-q1)
@@ -450,18 +437,18 @@ static uint8x16_t NeedsFilter(const uint8x16_t p1, const uint8x16_t p0,
return mask;
}
-static int8x16_t FlipSign(const uint8x16_t v) {
+static int8x16_t FlipSign_NEON(const uint8x16_t v) {
const uint8x16_t sign_bit = vdupq_n_u8(0x80);
return vreinterpretq_s8_u8(veorq_u8(v, sign_bit));
}
-static uint8x16_t FlipSignBack(const int8x16_t v) {
+static uint8x16_t FlipSignBack_NEON(const int8x16_t v) {
const int8x16_t sign_bit = vdupq_n_s8(0x80);
return vreinterpretq_u8_s8(veorq_s8(v, sign_bit));
}
-static int8x16_t GetBaseDelta(const int8x16_t p1, const int8x16_t p0,
- const int8x16_t q0, const int8x16_t q1) {
+static int8x16_t GetBaseDelta_NEON(const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1) {
const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0)
const int8x16_t p1_q1 = vqsubq_s8(p1, q1); // (p1-q1)
const int8x16_t s1 = vqaddq_s8(p1_q1, q0_p0); // (p1-q1) + 1 * (q0 - p0)
@@ -470,7 +457,7 @@ static int8x16_t GetBaseDelta(const int8x16_t p1, const int8x16_t p0,
return s3;
}
-static int8x16_t GetBaseDelta0(const int8x16_t p0, const int8x16_t q0) {
+static int8x16_t GetBaseDelta0_NEON(const int8x16_t p0, const int8x16_t q0) {
const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0)
const int8x16_t s1 = vqaddq_s8(q0_p0, q0_p0); // 2 * (q0 - p0)
const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // 3 * (q0 - p0)
@@ -479,9 +466,10 @@ static int8x16_t GetBaseDelta0(const int8x16_t p0, const int8x16_t q0) {
//------------------------------------------------------------------------------
-static void ApplyFilter2NoFlip(const int8x16_t p0s, const int8x16_t q0s,
- const int8x16_t delta,
- int8x16_t* const op0, int8x16_t* const oq0) {
+static void ApplyFilter2NoFlip_NEON(const int8x16_t p0s, const int8x16_t q0s,
+ const int8x16_t delta,
+ int8x16_t* const op0,
+ int8x16_t* const oq0) {
const int8x16_t kCst3 = vdupq_n_s8(0x03);
const int8x16_t kCst4 = vdupq_n_s8(0x04);
const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3);
@@ -494,9 +482,9 @@ static void ApplyFilter2NoFlip(const int8x16_t p0s, const int8x16_t q0s,
#if defined(WEBP_USE_INTRINSICS)
-static void ApplyFilter2(const int8x16_t p0s, const int8x16_t q0s,
- const int8x16_t delta,
- uint8x16_t* const op0, uint8x16_t* const oq0) {
+static void ApplyFilter2_NEON(const int8x16_t p0s, const int8x16_t q0s,
+ const int8x16_t delta,
+ uint8x16_t* const op0, uint8x16_t* const oq0) {
const int8x16_t kCst3 = vdupq_n_s8(0x03);
const int8x16_t kCst4 = vdupq_n_s8(0x04);
const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3);
@@ -505,45 +493,66 @@ static void ApplyFilter2(const int8x16_t p0s, const int8x16_t q0s,
const int8x16_t delta4 = vshrq_n_s8(delta_p4, 3);
const int8x16_t sp0 = vqaddq_s8(p0s, delta3);
const int8x16_t sq0 = vqsubq_s8(q0s, delta4);
- *op0 = FlipSignBack(sp0);
- *oq0 = FlipSignBack(sq0);
-}
-
-static void DoFilter2(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- const uint8x16_t mask,
- uint8x16_t* const op0, uint8x16_t* const oq0) {
- const int8x16_t p1s = FlipSign(p1);
- const int8x16_t p0s = FlipSign(p0);
- const int8x16_t q0s = FlipSign(q0);
- const int8x16_t q1s = FlipSign(q1);
- const int8x16_t delta0 = GetBaseDelta(p1s, p0s, q0s, q1s);
+ *op0 = FlipSignBack_NEON(sp0);
+ *oq0 = FlipSignBack_NEON(sq0);
+}
+
+static void DoFilter2_NEON(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t mask,
+ uint8x16_t* const op0, uint8x16_t* const oq0) {
+ const int8x16_t p1s = FlipSign_NEON(p1);
+ const int8x16_t p0s = FlipSign_NEON(p0);
+ const int8x16_t q0s = FlipSign_NEON(q0);
+ const int8x16_t q1s = FlipSign_NEON(q1);
+ const int8x16_t delta0 = GetBaseDelta_NEON(p1s, p0s, q0s, q1s);
const int8x16_t delta1 = vandq_s8(delta0, vreinterpretq_s8_u8(mask));
- ApplyFilter2(p0s, q0s, delta1, op0, oq0);
+ ApplyFilter2_NEON(p0s, q0s, delta1, op0, oq0);
}
-static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16_NEON(uint8_t* p, int stride, int thresh) {
uint8x16_t p1, p0, q0, q1, op0, oq0;
- Load16x4(p, stride, &p1, &p0, &q0, &q1);
+ Load16x4_NEON(p, stride, &p1, &p0, &q0, &q1);
{
- const uint8x16_t mask = NeedsFilter(p1, p0, q0, q1, thresh);
- DoFilter2(p1, p0, q0, q1, mask, &op0, &oq0);
+ const uint8x16_t mask = NeedsFilter_NEON(p1, p0, q0, q1, thresh);
+ DoFilter2_NEON(p1, p0, q0, q1, mask, &op0, &oq0);
}
- Store16x2(op0, oq0, p, stride);
+ Store16x2_NEON(op0, oq0, p, stride);
}
-static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16_NEON(uint8_t* p, int stride, int thresh) {
uint8x16_t p1, p0, q0, q1, oq0, op0;
- Load4x16(p, stride, &p1, &p0, &q0, &q1);
+ Load4x16_NEON(p, stride, &p1, &p0, &q0, &q1);
{
- const uint8x16_t mask = NeedsFilter(p1, p0, q0, q1, thresh);
- DoFilter2(p1, p0, q0, q1, mask, &op0, &oq0);
+ const uint8x16_t mask = NeedsFilter_NEON(p1, p0, q0, q1, thresh);
+ DoFilter2_NEON(p1, p0, q0, q1, mask, &op0, &oq0);
}
- Store2x16(op0, oq0, p, stride);
+ Store2x16_NEON(op0, oq0, p, stride);
}
#else
+// Load/Store vertical edge
+#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
+ "vld4.8 {" #c1 "[0]," #c2 "[0]," #c3 "[0]," #c4 "[0]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[1]," #c2 "[1]," #c3 "[1]," #c4 "[1]}," #b2 "," #stride "\n" \
+ "vld4.8 {" #c1 "[2]," #c2 "[2]," #c3 "[2]," #c4 "[2]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[3]," #c2 "[3]," #c3 "[3]," #c4 "[3]}," #b2 "," #stride "\n" \
+ "vld4.8 {" #c1 "[4]," #c2 "[4]," #c3 "[4]," #c4 "[4]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[5]," #c2 "[5]," #c3 "[5]," #c4 "[5]}," #b2 "," #stride "\n" \
+ "vld4.8 {" #c1 "[6]," #c2 "[6]," #c3 "[6]," #c4 "[6]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[7]," #c2 "[7]," #c3 "[7]," #c4 "[7]}," #b2 "," #stride "\n"
+
+#define STORE8x2(c1, c2, p, stride) \
+ "vst2.8 {" #c1 "[0], " #c2 "[0]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[1], " #c2 "[1]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[2], " #c2 "[2]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[3], " #c2 "[3]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[4], " #c2 "[4]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[5], " #c2 "[5]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[6], " #c2 "[6]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[7], " #c2 "[7]}," #p "," #stride " \n"
+
#define QRegs "q0", "q1", "q2", "q3", \
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
@@ -592,7 +601,7 @@ static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
DO_SIMPLE_FILTER(p0, q0, q9) /* apply filter */ \
FLIP_SIGN_BIT2(p0, q0, q10)
-static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16_NEON(uint8_t* p, int stride, int thresh) {
__asm__ volatile (
"sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
@@ -613,7 +622,7 @@ static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
);
}
-static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16_NEON(uint8_t* p, int stride, int thresh) {
__asm__ volatile (
"sub r4, %[p], #2 \n" // base1 = p - 2
"lsl r6, %[stride], #1 \n" // r6 = 2 * stride
@@ -639,30 +648,33 @@ static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
);
}
+#undef LOAD8x4
+#undef STORE8x2
+
#endif // WEBP_USE_INTRINSICS
-static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16i_NEON(uint8_t* p, int stride, int thresh) {
uint32_t k;
for (k = 3; k != 0; --k) {
p += 4 * stride;
- SimpleVFilter16(p, stride, thresh);
+ SimpleVFilter16_NEON(p, stride, thresh);
}
}
-static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16i_NEON(uint8_t* p, int stride, int thresh) {
uint32_t k;
for (k = 3; k != 0; --k) {
p += 4;
- SimpleHFilter16(p, stride, thresh);
+ SimpleHFilter16_NEON(p, stride, thresh);
}
}
//------------------------------------------------------------------------------
// Complex In-loop filtering (Paragraph 15.3)
-static uint8x16_t NeedsHev(const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- int hev_thresh) {
+static uint8x16_t NeedsHev_NEON(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ int hev_thresh) {
const uint8x16_t hev_thresh_v = vdupq_n_u8((uint8_t)hev_thresh);
const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0)
const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0)
@@ -671,11 +683,11 @@ static uint8x16_t NeedsHev(const uint8x16_t p1, const uint8x16_t p0,
return mask;
}
-static uint8x16_t NeedsFilter2(const uint8x16_t p3, const uint8x16_t p2,
- const uint8x16_t p1, const uint8x16_t p0,
- const uint8x16_t q0, const uint8x16_t q1,
- const uint8x16_t q2, const uint8x16_t q3,
- int ithresh, int thresh) {
+static uint8x16_t NeedsFilter2_NEON(const uint8x16_t p3, const uint8x16_t p2,
+ const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t q2, const uint8x16_t q3,
+ int ithresh, int thresh) {
const uint8x16_t ithresh_v = vdupq_n_u8((uint8_t)ithresh);
const uint8x16_t a_p3_p2 = vabdq_u8(p3, p2); // abs(p3 - p2)
const uint8x16_t a_p2_p1 = vabdq_u8(p2, p1); // abs(p2 - p1)
@@ -689,14 +701,14 @@ static uint8x16_t NeedsFilter2(const uint8x16_t p3, const uint8x16_t p2,
const uint8x16_t max12 = vmaxq_u8(max1, max2);
const uint8x16_t max123 = vmaxq_u8(max12, max3);
const uint8x16_t mask2 = vcgeq_u8(ithresh_v, max123);
- const uint8x16_t mask1 = NeedsFilter(p1, p0, q0, q1, thresh);
+ const uint8x16_t mask1 = NeedsFilter_NEON(p1, p0, q0, q1, thresh);
const uint8x16_t mask = vandq_u8(mask1, mask2);
return mask;
}
// 4-points filter
-static void ApplyFilter4(
+static void ApplyFilter4_NEON(
const int8x16_t p1, const int8x16_t p0,
const int8x16_t q0, const int8x16_t q1,
const int8x16_t delta0,
@@ -709,47 +721,47 @@ static void ApplyFilter4(
const int8x16_t a1 = vshrq_n_s8(delta1, 3);
const int8x16_t a2 = vshrq_n_s8(delta2, 3);
const int8x16_t a3 = vrshrq_n_s8(a1, 1); // a3 = (a1 + 1) >> 1
- *op0 = FlipSignBack(vqaddq_s8(p0, a2)); // clip(p0 + a2)
- *oq0 = FlipSignBack(vqsubq_s8(q0, a1)); // clip(q0 - a1)
- *op1 = FlipSignBack(vqaddq_s8(p1, a3)); // clip(p1 + a3)
- *oq1 = FlipSignBack(vqsubq_s8(q1, a3)); // clip(q1 - a3)
+ *op0 = FlipSignBack_NEON(vqaddq_s8(p0, a2)); // clip(p0 + a2)
+ *oq0 = FlipSignBack_NEON(vqsubq_s8(q0, a1)); // clip(q0 - a1)
+ *op1 = FlipSignBack_NEON(vqaddq_s8(p1, a3)); // clip(p1 + a3)
+ *oq1 = FlipSignBack_NEON(vqsubq_s8(q1, a3)); // clip(q1 - a3)
}
-static void DoFilter4(
+static void DoFilter4_NEON(
const uint8x16_t p1, const uint8x16_t p0,
const uint8x16_t q0, const uint8x16_t q1,
const uint8x16_t mask, const uint8x16_t hev_mask,
uint8x16_t* const op1, uint8x16_t* const op0,
uint8x16_t* const oq0, uint8x16_t* const oq1) {
// This is a fused version of DoFilter2() calling ApplyFilter2 directly
- const int8x16_t p1s = FlipSign(p1);
- int8x16_t p0s = FlipSign(p0);
- int8x16_t q0s = FlipSign(q0);
- const int8x16_t q1s = FlipSign(q1);
+ const int8x16_t p1s = FlipSign_NEON(p1);
+ int8x16_t p0s = FlipSign_NEON(p0);
+ int8x16_t q0s = FlipSign_NEON(q0);
+ const int8x16_t q1s = FlipSign_NEON(q1);
const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask);
// do_filter2 part (simple loopfilter on pixels with hev)
{
- const int8x16_t delta = GetBaseDelta(p1s, p0s, q0s, q1s);
+ const int8x16_t delta = GetBaseDelta_NEON(p1s, p0s, q0s, q1s);
const int8x16_t simple_lf_delta =
vandq_s8(delta, vreinterpretq_s8_u8(simple_lf_mask));
- ApplyFilter2NoFlip(p0s, q0s, simple_lf_delta, &p0s, &q0s);
+ ApplyFilter2NoFlip_NEON(p0s, q0s, simple_lf_delta, &p0s, &q0s);
}
// do_filter4 part (complex loopfilter on pixels without hev)
{
- const int8x16_t delta0 = GetBaseDelta0(p0s, q0s);
+ const int8x16_t delta0 = GetBaseDelta0_NEON(p0s, q0s);
// we use: (mask & hev_mask) ^ mask = mask & !hev_mask
const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask);
const int8x16_t complex_lf_delta =
vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask));
- ApplyFilter4(p1s, p0s, q0s, q1s, complex_lf_delta, op1, op0, oq0, oq1);
+ ApplyFilter4_NEON(p1s, p0s, q0s, q1s, complex_lf_delta, op1, op0, oq0, oq1);
}
}
// 6-points filter
-static void ApplyFilter6(
+static void ApplyFilter6_NEON(
const int8x16_t p2, const int8x16_t p1, const int8x16_t p0,
const int8x16_t q0, const int8x16_t q1, const int8x16_t q2,
const int8x16_t delta,
@@ -778,35 +790,35 @@ static void ApplyFilter6(
const int8x16_t a2 = vcombine_s8(a2_lo, a2_hi);
const int8x16_t a3 = vcombine_s8(a3_lo, a3_hi);
- *op0 = FlipSignBack(vqaddq_s8(p0, a1)); // clip(p0 + a1)
- *oq0 = FlipSignBack(vqsubq_s8(q0, a1)); // clip(q0 - q1)
- *oq1 = FlipSignBack(vqsubq_s8(q1, a2)); // clip(q1 - a2)
- *op1 = FlipSignBack(vqaddq_s8(p1, a2)); // clip(p1 + a2)
- *oq2 = FlipSignBack(vqsubq_s8(q2, a3)); // clip(q2 - a3)
- *op2 = FlipSignBack(vqaddq_s8(p2, a3)); // clip(p2 + a3)
+ *op0 = FlipSignBack_NEON(vqaddq_s8(p0, a1)); // clip(p0 + a1)
+ *oq0 = FlipSignBack_NEON(vqsubq_s8(q0, a1)); // clip(q0 - q1)
+ *oq1 = FlipSignBack_NEON(vqsubq_s8(q1, a2)); // clip(q1 - a2)
+ *op1 = FlipSignBack_NEON(vqaddq_s8(p1, a2)); // clip(p1 + a2)
+ *oq2 = FlipSignBack_NEON(vqsubq_s8(q2, a3)); // clip(q2 - a3)
+ *op2 = FlipSignBack_NEON(vqaddq_s8(p2, a3)); // clip(p2 + a3)
}
-static void DoFilter6(
+static void DoFilter6_NEON(
const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0,
const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2,
const uint8x16_t mask, const uint8x16_t hev_mask,
uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0,
uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) {
// This is a fused version of DoFilter2() calling ApplyFilter2 directly
- const int8x16_t p2s = FlipSign(p2);
- const int8x16_t p1s = FlipSign(p1);
- int8x16_t p0s = FlipSign(p0);
- int8x16_t q0s = FlipSign(q0);
- const int8x16_t q1s = FlipSign(q1);
- const int8x16_t q2s = FlipSign(q2);
+ const int8x16_t p2s = FlipSign_NEON(p2);
+ const int8x16_t p1s = FlipSign_NEON(p1);
+ int8x16_t p0s = FlipSign_NEON(p0);
+ int8x16_t q0s = FlipSign_NEON(q0);
+ const int8x16_t q1s = FlipSign_NEON(q1);
+ const int8x16_t q2s = FlipSign_NEON(q2);
const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask);
- const int8x16_t delta0 = GetBaseDelta(p1s, p0s, q0s, q1s);
+ const int8x16_t delta0 = GetBaseDelta_NEON(p1s, p0s, q0s, q1s);
// do_filter2 part (simple loopfilter on pixels with hev)
{
const int8x16_t simple_lf_delta =
vandq_s8(delta0, vreinterpretq_s8_u8(simple_lf_mask));
- ApplyFilter2NoFlip(p0s, q0s, simple_lf_delta, &p0s, &q0s);
+ ApplyFilter2NoFlip_NEON(p0s, q0s, simple_lf_delta, &p0s, &q0s);
}
// do_filter6 part (complex loopfilter on pixels without hev)
@@ -815,65 +827,65 @@ static void DoFilter6(
const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask);
const int8x16_t complex_lf_delta =
vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask));
- ApplyFilter6(p2s, p1s, p0s, q0s, q1s, q2s, complex_lf_delta,
- op2, op1, op0, oq0, oq1, oq2);
+ ApplyFilter6_NEON(p2s, p1s, p0s, q0s, q1s, q2s, complex_lf_delta,
+ op2, op1, op0, oq0, oq1, oq2);
}
}
// on macroblock edges
-static void VFilter16(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16_NEON(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
- Load16x8(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ Load16x8_NEON(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
{
- const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
- ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
uint8x16_t op2, op1, op0, oq0, oq1, oq2;
- DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
- &op2, &op1, &op0, &oq0, &oq1, &oq2);
- Store16x2(op2, op1, p - 2 * stride, stride);
- Store16x2(op0, oq0, p + 0 * stride, stride);
- Store16x2(oq1, oq2, p + 2 * stride, stride);
+ DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store16x2_NEON(op2, op1, p - 2 * stride, stride);
+ Store16x2_NEON(op0, oq0, p + 0 * stride, stride);
+ Store16x2_NEON(oq1, oq2, p + 2 * stride, stride);
}
}
-static void HFilter16(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16_NEON(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
- Load8x16(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ Load8x16_NEON(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
{
- const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
- ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
uint8x16_t op2, op1, op0, oq0, oq1, oq2;
- DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
- &op2, &op1, &op0, &oq0, &oq1, &oq2);
- Store2x16(op2, op1, p - 2, stride);
- Store2x16(op0, oq0, p + 0, stride);
- Store2x16(oq1, oq2, p + 2, stride);
+ DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store2x16_NEON(op2, op1, p - 2, stride);
+ Store2x16_NEON(op0, oq0, p + 0, stride);
+ Store2x16_NEON(oq1, oq2, p + 2, stride);
}
}
// on three inner edges
-static void VFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16i_NEON(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint32_t k;
uint8x16_t p3, p2, p1, p0;
- Load16x4(p + 2 * stride, stride, &p3, &p2, &p1, &p0);
+ Load16x4_NEON(p + 2 * stride, stride, &p3, &p2, &p1, &p0);
for (k = 3; k != 0; --k) {
uint8x16_t q0, q1, q2, q3;
p += 4 * stride;
- Load16x4(p + 2 * stride, stride, &q0, &q1, &q2, &q3);
+ Load16x4_NEON(p + 2 * stride, stride, &q0, &q1, &q2, &q3);
{
const uint8x16_t mask =
- NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
// p3 and p2 are not just temporary variables here: they will be
// re-used for next span. And q2/q3 will become p1/p0 accordingly.
- DoFilter4(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
- Store16x4(p1, p0, p3, p2, p, stride);
+ DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
+ Store16x4_NEON(p1, p0, p3, p2, p, stride);
p1 = q2;
p0 = q3;
}
@@ -881,21 +893,21 @@ static void VFilter16i(uint8_t* p, int stride,
}
#if !defined(WORK_AROUND_GCC)
-static void HFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16i_NEON(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint32_t k;
uint8x16_t p3, p2, p1, p0;
- Load4x16(p + 2, stride, &p3, &p2, &p1, &p0);
+ Load4x16_NEON(p + 2, stride, &p3, &p2, &p1, &p0);
for (k = 3; k != 0; --k) {
uint8x16_t q0, q1, q2, q3;
p += 4;
- Load4x16(p + 2, stride, &q0, &q1, &q2, &q3);
+ Load4x16_NEON(p + 2, stride, &q0, &q1, &q2, &q3);
{
const uint8x16_t mask =
- NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
- DoFilter4(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
- Store4x16(p1, p0, p3, p2, p, stride);
+ NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
+ DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
+ Store4x16_NEON(p1, p0, p3, p2, p, stride);
p1 = q2;
p0 = q3;
}
@@ -904,67 +916,67 @@ static void HFilter16i(uint8_t* p, int stride,
#endif // !WORK_AROUND_GCC
// 8-pixels wide variant, for chroma filtering
-static void VFilter8(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8_NEON(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
- Load8x8x2(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ Load8x8x2_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
{
- const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
- ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
uint8x16_t op2, op1, op0, oq0, oq1, oq2;
- DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
- &op2, &op1, &op0, &oq0, &oq1, &oq2);
- Store8x2x2(op2, op1, u - 2 * stride, v - 2 * stride, stride);
- Store8x2x2(op0, oq0, u + 0 * stride, v + 0 * stride, stride);
- Store8x2x2(oq1, oq2, u + 2 * stride, v + 2 * stride, stride);
+ DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store8x2x2_NEON(op2, op1, u - 2 * stride, v - 2 * stride, stride);
+ Store8x2x2_NEON(op0, oq0, u + 0 * stride, v + 0 * stride, stride);
+ Store8x2x2_NEON(oq1, oq2, u + 2 * stride, v + 2 * stride, stride);
}
}
-static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8i_NEON(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
u += 4 * stride;
v += 4 * stride;
- Load8x8x2(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ Load8x8x2_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
{
- const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
- ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
uint8x16_t op1, op0, oq0, oq1;
- DoFilter4(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
- Store8x4x2(op1, op0, oq0, oq1, u, v, stride);
+ DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
+ Store8x4x2_NEON(op1, op0, oq0, oq1, u, v, stride);
}
}
#if !defined(WORK_AROUND_GCC)
-static void HFilter8(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8_NEON(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
- Load8x8x2T(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ Load8x8x2T_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
{
- const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
- ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
uint8x16_t op2, op1, op0, oq0, oq1, oq2;
- DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
- &op2, &op1, &op0, &oq0, &oq1, &oq2);
- Store6x8x2(op2, op1, op0, oq0, oq1, oq2, u, v, stride);
+ DoFilter6_NEON(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store6x8x2_NEON(op2, op1, op0, oq0, oq1, oq2, u, v, stride);
}
}
-static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8i_NEON(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
u += 4;
v += 4;
- Load8x8x2T(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ Load8x8x2T_NEON(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
{
- const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
- ithresh, thresh);
- const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ const uint8x16_t mask = NeedsFilter2_NEON(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev_NEON(p1, p0, q0, q1, hev_thresh);
uint8x16_t op1, op0, oq0, oq1;
- DoFilter4(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
- Store4x8x2(op1, op0, oq0, oq1, u, v, stride);
+ DoFilter4_NEON(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
+ Store4x8x2_NEON(op1, op0, oq0, oq1, u, v, stride);
}
}
#endif // !WORK_AROUND_GCC
@@ -992,8 +1004,9 @@ static const int16_t kC1 = 20091;
static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
#if defined(WEBP_USE_INTRINSICS)
-static WEBP_INLINE void Transpose8x2(const int16x8_t in0, const int16x8_t in1,
- int16x8x2_t* const out) {
+static WEBP_INLINE void Transpose8x2_NEON(const int16x8_t in0,
+ const int16x8_t in1,
+ int16x8x2_t* const out) {
// a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1
// c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3
const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ...
@@ -1001,7 +1014,7 @@ static WEBP_INLINE void Transpose8x2(const int16x8_t in0, const int16x8_t in1,
*out = vzipq_s16(tmp0.val[0], tmp0.val[1]);
}
-static WEBP_INLINE void TransformPass(int16x8x2_t* const rows) {
+static WEBP_INLINE void TransformPass_NEON(int16x8x2_t* const rows) {
// {rows} = in0 | in4
// in8 | in12
// B1 = in4 | in12
@@ -1024,20 +1037,20 @@ static WEBP_INLINE void TransformPass(int16x8x2_t* const rows) {
const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c
const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c
const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp));
- Transpose8x2(E0, E1, rows);
+ Transpose8x2_NEON(E0, E1, rows);
}
-static void TransformOne(const int16_t* in, uint8_t* dst) {
+static void TransformOne_NEON(const int16_t* in, uint8_t* dst) {
int16x8x2_t rows;
INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8));
- TransformPass(&rows);
- TransformPass(&rows);
- Add4x4(rows.val[0], rows.val[1], dst);
+ TransformPass_NEON(&rows);
+ TransformPass_NEON(&rows);
+ Add4x4_NEON(rows.val[0], rows.val[1], dst);
}
#else
-static void TransformOne(const int16_t* in, uint8_t* dst) {
+static void TransformOne_NEON(const int16_t* in, uint8_t* dst) {
const int kBPS = BPS;
// kC1, kC2. Padded because vld1.16 loads 8 bytes
const int16_t constants[4] = { kC1, kC2, 0, 0 };
@@ -1170,16 +1183,16 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
#endif // WEBP_USE_INTRINSICS
-static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
- TransformOne(in, dst);
+static void TransformTwo_NEON(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne_NEON(in, dst);
if (do_two) {
- TransformOne(in + 16, dst + 4);
+ TransformOne_NEON(in + 16, dst + 4);
}
}
-static void TransformDC(const int16_t* in, uint8_t* dst) {
+static void TransformDC_NEON(const int16_t* in, uint8_t* dst) {
const int16x8_t DC = vdupq_n_s16(in[0]);
- Add4x4(DC, DC, dst);
+ Add4x4_NEON(DC, DC, dst);
}
//------------------------------------------------------------------------------
@@ -1191,7 +1204,7 @@ static void TransformDC(const int16_t* in, uint8_t* dst) {
*dst = vgetq_lane_s32(rows.val[3], col); (dst) += 16; \
} while (0)
-static void TransformWHT(const int16_t* in, int16_t* out) {
+static void TransformWHT_NEON(const int16_t* in, int16_t* out) {
int32x4x4_t tmp;
{
@@ -1209,7 +1222,7 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
tmp.val[2] = vsubq_s32(a0, a1);
tmp.val[3] = vsubq_s32(a3, a2);
// Arrange the temporary results column-wise.
- tmp = Transpose4x4(tmp);
+ tmp = Transpose4x4_NEON(tmp);
}
{
@@ -1243,7 +1256,7 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
//------------------------------------------------------------------------------
#define MUL(a, b) (((a) * (b)) >> 16)
-static void TransformAC3(const int16_t* in, uint8_t* dst) {
+static void TransformAC3_NEON(const int16_t* in, uint8_t* dst) {
static const int kC1_full = 20091 + (1 << 16);
static const int kC2_full = 35468;
const int16x4_t A = vld1_dup_s16(in);
@@ -1259,14 +1272,14 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
const int16x4_t B = vqadd_s16(A, CD);
const int16x8_t m0_m1 = vcombine_s16(vqadd_s16(B, d4), vqadd_s16(B, c4));
const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4));
- Add4x4(m0_m1, m2_m3, dst);
+ Add4x4_NEON(m0_m1, m2_m3, dst);
}
#undef MUL
//------------------------------------------------------------------------------
// 4x4
-static void DC4(uint8_t* dst) { // DC
+static void DC4_NEON(uint8_t* dst) { // DC
const uint8x8_t A = vld1_u8(dst - BPS); // top row
const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top
const uint16x4_t p1 = vpadd_u16(p0, p0);
@@ -1287,17 +1300,17 @@ static void DC4(uint8_t* dst) { // DC
}
// TrueMotion (4x4 + 8x8)
-static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
+static WEBP_INLINE void TrueMotion_NEON(uint8_t* dst, int size) {
const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]'
const uint8x8_t T = vld1_u8(dst - BPS); // top row 'A[0..3]'
const int16x8_t d = vreinterpretq_s16_u16(vsubl_u8(T, TL)); // A[c] - A[-1]
int y;
for (y = 0; y < size; y += 4) {
// left edge
- const int16x8_t L0 = ConvertU8ToS16(vld1_dup_u8(dst + 0 * BPS - 1));
- const int16x8_t L1 = ConvertU8ToS16(vld1_dup_u8(dst + 1 * BPS - 1));
- const int16x8_t L2 = ConvertU8ToS16(vld1_dup_u8(dst + 2 * BPS - 1));
- const int16x8_t L3 = ConvertU8ToS16(vld1_dup_u8(dst + 3 * BPS - 1));
+ const int16x8_t L0 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 0 * BPS - 1));
+ const int16x8_t L1 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 1 * BPS - 1));
+ const int16x8_t L2 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 2 * BPS - 1));
+ const int16x8_t L3 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 3 * BPS - 1));
const int16x8_t r0 = vaddq_s16(L0, d); // L[r] + A[c] - A[-1]
const int16x8_t r1 = vaddq_s16(L1, d);
const int16x8_t r2 = vaddq_s16(L2, d);
@@ -1322,9 +1335,9 @@ static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
}
}
-static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
+static void TM4_NEON(uint8_t* dst) { TrueMotion_NEON(dst, 4); }
-static void VE4(uint8_t* dst) { // vertical
+static void VE4_NEON(uint8_t* dst) { // vertical
// NB: avoid vld1_u64 here as an alignment hint may be added -> SIGBUS.
const uint64x1_t A0 = vreinterpret_u64_u8(vld1_u8(dst - BPS - 1)); // top row
const uint64x1_t A1 = vshr_n_u64(A0, 8);
@@ -1340,7 +1353,7 @@ static void VE4(uint8_t* dst) { // vertical
}
}
-static void RD4(uint8_t* dst) { // Down-right
+static void RD4_NEON(uint8_t* dst) { // Down-right
const uint8x8_t XABCD_u8 = vld1_u8(dst - BPS - 1);
const uint64x1_t XABCD = vreinterpret_u64_u8(XABCD_u8);
const uint64x1_t ____XABC = vshl_n_u64(XABCD, 32);
@@ -1368,7 +1381,7 @@ static void RD4(uint8_t* dst) { // Down-right
vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3, 0);
}
-static void LD4(uint8_t* dst) { // Down-left
+static void LD4_NEON(uint8_t* dst) { // Down-left
// Note using the same shift trick as VE4() is slower here.
const uint8x8_t ABCDEFGH = vld1_u8(dst - BPS + 0);
const uint8x8_t BCDEFGH0 = vld1_u8(dst - BPS + 1);
@@ -1390,7 +1403,7 @@ static void LD4(uint8_t* dst) { // Down-left
//------------------------------------------------------------------------------
// Chroma
-static void VE8uv(uint8_t* dst) { // vertical
+static void VE8uv_NEON(uint8_t* dst) { // vertical
const uint8x8_t top = vld1_u8(dst - BPS);
int j;
for (j = 0; j < 8; ++j) {
@@ -1398,7 +1411,7 @@ static void VE8uv(uint8_t* dst) { // vertical
}
}
-static void HE8uv(uint8_t* dst) { // horizontal
+static void HE8uv_NEON(uint8_t* dst) { // horizontal
int j;
for (j = 0; j < 8; ++j) {
const uint8x8_t left = vld1_dup_u8(dst - 1);
@@ -1407,7 +1420,7 @@ static void HE8uv(uint8_t* dst) { // horizontal
}
}
-static WEBP_INLINE void DC8(uint8_t* dst, int do_top, int do_left) {
+static WEBP_INLINE void DC8_NEON(uint8_t* dst, int do_top, int do_left) {
uint16x8_t sum_top;
uint16x8_t sum_left;
uint8x8_t dc0;
@@ -1458,17 +1471,17 @@ static WEBP_INLINE void DC8(uint8_t* dst, int do_top, int do_left) {
}
}
-static void DC8uv(uint8_t* dst) { DC8(dst, 1, 1); }
-static void DC8uvNoTop(uint8_t* dst) { DC8(dst, 0, 1); }
-static void DC8uvNoLeft(uint8_t* dst) { DC8(dst, 1, 0); }
-static void DC8uvNoTopLeft(uint8_t* dst) { DC8(dst, 0, 0); }
+static void DC8uv_NEON(uint8_t* dst) { DC8_NEON(dst, 1, 1); }
+static void DC8uvNoTop_NEON(uint8_t* dst) { DC8_NEON(dst, 0, 1); }
+static void DC8uvNoLeft_NEON(uint8_t* dst) { DC8_NEON(dst, 1, 0); }
+static void DC8uvNoTopLeft_NEON(uint8_t* dst) { DC8_NEON(dst, 0, 0); }
-static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
+static void TM8uv_NEON(uint8_t* dst) { TrueMotion_NEON(dst, 8); }
//------------------------------------------------------------------------------
// 16x16
-static void VE16(uint8_t* dst) { // vertical
+static void VE16_NEON(uint8_t* dst) { // vertical
const uint8x16_t top = vld1q_u8(dst - BPS);
int j;
for (j = 0; j < 16; ++j) {
@@ -1476,7 +1489,7 @@ static void VE16(uint8_t* dst) { // vertical
}
}
-static void HE16(uint8_t* dst) { // horizontal
+static void HE16_NEON(uint8_t* dst) { // horizontal
int j;
for (j = 0; j < 16; ++j) {
const uint8x16_t left = vld1q_dup_u8(dst - 1);
@@ -1485,7 +1498,7 @@ static void HE16(uint8_t* dst) { // horizontal
}
}
-static WEBP_INLINE void DC16(uint8_t* dst, int do_top, int do_left) {
+static WEBP_INLINE void DC16_NEON(uint8_t* dst, int do_top, int do_left) {
uint16x8_t sum_top;
uint16x8_t sum_left;
uint8x8_t dc0;
@@ -1542,12 +1555,12 @@ static WEBP_INLINE void DC16(uint8_t* dst, int do_top, int do_left) {
}
}
-static void DC16TopLeft(uint8_t* dst) { DC16(dst, 1, 1); }
-static void DC16NoTop(uint8_t* dst) { DC16(dst, 0, 1); }
-static void DC16NoLeft(uint8_t* dst) { DC16(dst, 1, 0); }
-static void DC16NoTopLeft(uint8_t* dst) { DC16(dst, 0, 0); }
+static void DC16TopLeft_NEON(uint8_t* dst) { DC16_NEON(dst, 1, 1); }
+static void DC16NoTop_NEON(uint8_t* dst) { DC16_NEON(dst, 0, 1); }
+static void DC16NoLeft_NEON(uint8_t* dst) { DC16_NEON(dst, 1, 0); }
+static void DC16NoTopLeft_NEON(uint8_t* dst) { DC16_NEON(dst, 0, 0); }
-static void TM16(uint8_t* dst) {
+static void TM16_NEON(uint8_t* dst) {
const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]'
const uint8x16_t T = vld1q_u8(dst - BPS); // top row 'A[0..15]'
// A[c] - A[-1]
@@ -1556,10 +1569,10 @@ static void TM16(uint8_t* dst) {
int y;
for (y = 0; y < 16; y += 4) {
// left edge
- const int16x8_t L0 = ConvertU8ToS16(vld1_dup_u8(dst + 0 * BPS - 1));
- const int16x8_t L1 = ConvertU8ToS16(vld1_dup_u8(dst + 1 * BPS - 1));
- const int16x8_t L2 = ConvertU8ToS16(vld1_dup_u8(dst + 2 * BPS - 1));
- const int16x8_t L3 = ConvertU8ToS16(vld1_dup_u8(dst + 3 * BPS - 1));
+ const int16x8_t L0 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 0 * BPS - 1));
+ const int16x8_t L1 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 1 * BPS - 1));
+ const int16x8_t L2 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 2 * BPS - 1));
+ const int16x8_t L3 = ConvertU8ToS16_NEON(vld1_dup_u8(dst + 3 * BPS - 1));
const int16x8_t r0_lo = vaddq_s16(L0, d_lo); // L[r] + A[c] - A[-1]
const int16x8_t r1_lo = vaddq_s16(L1, d_lo);
const int16x8_t r2_lo = vaddq_s16(L2, d_lo);
@@ -1587,49 +1600,49 @@ static void TM16(uint8_t* dst) {
extern void VP8DspInitNEON(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitNEON(void) {
- VP8Transform = TransformTwo;
- VP8TransformAC3 = TransformAC3;
- VP8TransformDC = TransformDC;
- VP8TransformWHT = TransformWHT;
-
- VP8VFilter16 = VFilter16;
- VP8VFilter16i = VFilter16i;
- VP8HFilter16 = HFilter16;
+ VP8Transform = TransformTwo_NEON;
+ VP8TransformAC3 = TransformAC3_NEON;
+ VP8TransformDC = TransformDC_NEON;
+ VP8TransformWHT = TransformWHT_NEON;
+
+ VP8VFilter16 = VFilter16_NEON;
+ VP8VFilter16i = VFilter16i_NEON;
+ VP8HFilter16 = HFilter16_NEON;
#if !defined(WORK_AROUND_GCC)
- VP8HFilter16i = HFilter16i;
+ VP8HFilter16i = HFilter16i_NEON;
#endif
- VP8VFilter8 = VFilter8;
- VP8VFilter8i = VFilter8i;
+ VP8VFilter8 = VFilter8_NEON;
+ VP8VFilter8i = VFilter8i_NEON;
#if !defined(WORK_AROUND_GCC)
- VP8HFilter8 = HFilter8;
- VP8HFilter8i = HFilter8i;
+ VP8HFilter8 = HFilter8_NEON;
+ VP8HFilter8i = HFilter8i_NEON;
#endif
- VP8SimpleVFilter16 = SimpleVFilter16;
- VP8SimpleHFilter16 = SimpleHFilter16;
- VP8SimpleVFilter16i = SimpleVFilter16i;
- VP8SimpleHFilter16i = SimpleHFilter16i;
-
- VP8PredLuma4[0] = DC4;
- VP8PredLuma4[1] = TM4;
- VP8PredLuma4[2] = VE4;
- VP8PredLuma4[4] = RD4;
- VP8PredLuma4[6] = LD4;
-
- VP8PredLuma16[0] = DC16TopLeft;
- VP8PredLuma16[1] = TM16;
- VP8PredLuma16[2] = VE16;
- VP8PredLuma16[3] = HE16;
- VP8PredLuma16[4] = DC16NoTop;
- VP8PredLuma16[5] = DC16NoLeft;
- VP8PredLuma16[6] = DC16NoTopLeft;
-
- VP8PredChroma8[0] = DC8uv;
- VP8PredChroma8[1] = TM8uv;
- VP8PredChroma8[2] = VE8uv;
- VP8PredChroma8[3] = HE8uv;
- VP8PredChroma8[4] = DC8uvNoTop;
- VP8PredChroma8[5] = DC8uvNoLeft;
- VP8PredChroma8[6] = DC8uvNoTopLeft;
+ VP8SimpleVFilter16 = SimpleVFilter16_NEON;
+ VP8SimpleHFilter16 = SimpleHFilter16_NEON;
+ VP8SimpleVFilter16i = SimpleVFilter16i_NEON;
+ VP8SimpleHFilter16i = SimpleHFilter16i_NEON;
+
+ VP8PredLuma4[0] = DC4_NEON;
+ VP8PredLuma4[1] = TM4_NEON;
+ VP8PredLuma4[2] = VE4_NEON;
+ VP8PredLuma4[4] = RD4_NEON;
+ VP8PredLuma4[6] = LD4_NEON;
+
+ VP8PredLuma16[0] = DC16TopLeft_NEON;
+ VP8PredLuma16[1] = TM16_NEON;
+ VP8PredLuma16[2] = VE16_NEON;
+ VP8PredLuma16[3] = HE16_NEON;
+ VP8PredLuma16[4] = DC16NoTop_NEON;
+ VP8PredLuma16[5] = DC16NoLeft_NEON;
+ VP8PredLuma16[6] = DC16NoTopLeft_NEON;
+
+ VP8PredChroma8[0] = DC8uv_NEON;
+ VP8PredChroma8[1] = TM8uv_NEON;
+ VP8PredChroma8[2] = VE8uv_NEON;
+ VP8PredChroma8[3] = HE8uv_NEON;
+ VP8PredChroma8[4] = DC8uvNoTop_NEON;
+ VP8PredChroma8[5] = DC8uvNoLeft_NEON;
+ VP8PredChroma8[6] = DC8uvNoTopLeft_NEON;
}
#else // !WEBP_USE_NEON
diff --git a/media/libwebp/dsp/dec_sse2.c b/media/libwebp/dsp/dec_sse2.c
index 411fb0276..f187a5bb4 100644
--- a/media/libwebp/dsp/dec_sse2.c
+++ b/media/libwebp/dsp/dec_sse2.c
@@ -12,23 +12,25 @@
// Author: somnath@google.com (Somnath Banerjee)
// cduvivier@google.com (Christian Duvivier)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE2)
// The 3-coeff sparse transform in SSE2 is not really faster than the plain-C
// one it seems => disable it by default. Uncomment the following to enable:
-// #define USE_TRANSFORM_AC3
+#if !defined(USE_TRANSFORM_AC3)
+#define USE_TRANSFORM_AC3 0 // ALTERNATE_CODE
+#endif
#include <emmintrin.h>
-#include "./common_sse2.h"
+#include "../dsp/common_sse2.h"
#include "../dec/vp8i_dec.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
-static void Transform(const int16_t* in, uint8_t* dst, int do_two) {
+static void Transform_SSE2(const int16_t* in, uint8_t* dst, int do_two) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
@@ -193,7 +195,7 @@ static void Transform(const int16_t* in, uint8_t* dst, int do_two) {
}
}
-#if defined(USE_TRANSFORM_AC3)
+#if (USE_TRANSFORM_AC3 == 1)
#define MUL(a, b) (((a) * (b)) >> 16)
static void TransformAC3(const int16_t* in, uint8_t* dst) {
static const int kC1 = 20091 + (1 << 16);
@@ -248,7 +250,7 @@ static void TransformAC3(const int16_t* in, uint8_t* dst) {
_mm_subs_epu8((p), (q)))
// Shift each byte of "x" by 3 bits while preserving by the sign bit.
-static WEBP_INLINE void SignedShift8b(__m128i* const x) {
+static WEBP_INLINE void SignedShift8b_SSE2(__m128i* const x) {
const __m128i zero = _mm_setzero_si128();
const __m128i lo_0 = _mm_unpacklo_epi8(zero, *x);
const __m128i hi_0 = _mm_unpackhi_epi8(zero, *x);
@@ -258,8 +260,8 @@ static WEBP_INLINE void SignedShift8b(__m128i* const x) {
}
#define FLIP_SIGN_BIT2(a, b) { \
- a = _mm_xor_si128(a, sign_bit); \
- b = _mm_xor_si128(b, sign_bit); \
+ (a) = _mm_xor_si128(a, sign_bit); \
+ (b) = _mm_xor_si128(b, sign_bit); \
}
#define FLIP_SIGN_BIT4(a, b, c, d) { \
@@ -268,11 +270,11 @@ static WEBP_INLINE void SignedShift8b(__m128i* const x) {
}
// input/output is uint8_t
-static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
- const __m128i* const p0,
- const __m128i* const q0,
- const __m128i* const q1,
- int hev_thresh, __m128i* const not_hev) {
+static WEBP_INLINE void GetNotHEV_SSE2(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int hev_thresh, __m128i* const not_hev) {
const __m128i zero = _mm_setzero_si128();
const __m128i t_1 = MM_ABS(*p1, *p0);
const __m128i t_2 = MM_ABS(*q1, *q0);
@@ -285,11 +287,11 @@ static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
}
// input pixels are int8_t
-static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
- const __m128i* const p0,
- const __m128i* const q0,
- const __m128i* const q1,
- __m128i* const delta) {
+static WEBP_INLINE void GetBaseDelta_SSE2(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ __m128i* const delta) {
// beware of addition order, for saturation!
const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0
@@ -300,15 +302,16 @@ static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
}
// input and output are int8_t
-static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
- const __m128i* const fl) {
+static WEBP_INLINE void DoSimpleFilter_SSE2(__m128i* const p0,
+ __m128i* const q0,
+ const __m128i* const fl) {
const __m128i k3 = _mm_set1_epi8(3);
const __m128i k4 = _mm_set1_epi8(4);
__m128i v3 = _mm_adds_epi8(*fl, k3);
__m128i v4 = _mm_adds_epi8(*fl, k4);
- SignedShift8b(&v4); // v4 >> 3
- SignedShift8b(&v3); // v3 >> 3
+ SignedShift8b_SSE2(&v4); // v4 >> 3
+ SignedShift8b_SSE2(&v3); // v3 >> 3
*q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4
*p0 = _mm_adds_epi8(*p0, v3); // p0 += v3
}
@@ -317,9 +320,9 @@ static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
// Update operations:
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip).
-static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
- const __m128i* const a0_lo,
- const __m128i* const a0_hi) {
+static WEBP_INLINE void Update2Pixels_SSE2(__m128i* const pi, __m128i* const qi,
+ const __m128i* const a0_lo,
+ const __m128i* const a0_hi) {
const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
@@ -330,11 +333,11 @@ static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
}
// input pixels are uint8_t
-static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
- const __m128i* const p0,
- const __m128i* const q0,
- const __m128i* const q1,
- int thresh, __m128i* const mask) {
+static WEBP_INLINE void NeedsFilter_SSE2(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int thresh, __m128i* const mask) {
const __m128i m_thresh = _mm_set1_epi8(thresh);
const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
const __m128i kFE = _mm_set1_epi8(0xFE);
@@ -353,28 +356,29 @@ static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
// Edge filtering functions
// Applies filter on 2 pixels (p0 and q0)
-static WEBP_INLINE void DoFilter2(__m128i* const p1, __m128i* const p0,
- __m128i* const q0, __m128i* const q1,
- int thresh) {
+static WEBP_INLINE void DoFilter2_SSE2(__m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1,
+ int thresh) {
__m128i a, mask;
const __m128i sign_bit = _mm_set1_epi8(0x80);
- // convert p1/q1 to int8_t (for GetBaseDelta)
+ // convert p1/q1 to int8_t (for GetBaseDelta_SSE2)
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
- NeedsFilter(p1, p0, q0, q1, thresh, &mask);
+ NeedsFilter_SSE2(p1, p0, q0, q1, thresh, &mask);
FLIP_SIGN_BIT2(*p0, *q0);
- GetBaseDelta(&p1s, p0, q0, &q1s, &a);
+ GetBaseDelta_SSE2(&p1s, p0, q0, &q1s, &a);
a = _mm_and_si128(a, mask); // mask filter values we don't care about
- DoSimpleFilter(p0, q0, &a);
+ DoSimpleFilter_SSE2(p0, q0, &a);
FLIP_SIGN_BIT2(*p0, *q0);
}
// Applies filter on 4 pixels (p1, p0, q0 and q1)
-static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
- __m128i* const q0, __m128i* const q1,
- const __m128i* const mask, int hev_thresh) {
+static WEBP_INLINE void DoFilter4_SSE2(__m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1,
+ const __m128i* const mask,
+ int hev_thresh) {
const __m128i zero = _mm_setzero_si128();
const __m128i sign_bit = _mm_set1_epi8(0x80);
const __m128i k64 = _mm_set1_epi8(64);
@@ -384,7 +388,7 @@ static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
__m128i t1, t2, t3;
// compute hev mask
- GetNotHEV(p1, p0, q0, q1, hev_thresh, &not_hev);
+ GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, &not_hev);
// convert to signed values
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
@@ -399,8 +403,8 @@ static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
t2 = _mm_adds_epi8(t1, k3); // 3 * (q0 - p0) + hev(p1 - q1) + 3
t3 = _mm_adds_epi8(t1, k4); // 3 * (q0 - p0) + hev(p1 - q1) + 4
- SignedShift8b(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
- SignedShift8b(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
+ SignedShift8b_SSE2(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
+ SignedShift8b_SSE2(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
*q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3
FLIP_SIGN_BIT2(*p0, *q0);
@@ -417,25 +421,26 @@ static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
}
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
-static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
- __m128i* const p0, __m128i* const q0,
- __m128i* const q1, __m128i* const q2,
- const __m128i* const mask, int hev_thresh) {
+static WEBP_INLINE void DoFilter6_SSE2(__m128i* const p2, __m128i* const p1,
+ __m128i* const p0, __m128i* const q0,
+ __m128i* const q1, __m128i* const q2,
+ const __m128i* const mask,
+ int hev_thresh) {
const __m128i zero = _mm_setzero_si128();
const __m128i sign_bit = _mm_set1_epi8(0x80);
__m128i a, not_hev;
// compute hev mask
- GetNotHEV(p1, p0, q0, q1, hev_thresh, &not_hev);
+ GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, &not_hev);
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
FLIP_SIGN_BIT2(*p2, *q2);
- GetBaseDelta(p1, p0, q0, q1, &a);
+ GetBaseDelta_SSE2(p1, p0, q0, q1, &a);
{ // do simple filter on pixels with hev
const __m128i m = _mm_andnot_si128(not_hev, *mask);
const __m128i f = _mm_and_si128(a, m);
- DoSimpleFilter(p0, q0, &f);
+ DoSimpleFilter_SSE2(p0, q0, &f);
}
{ // do strong filter on pixels with not hev
@@ -460,15 +465,15 @@ static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63
const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63
- Update2Pixels(p2, q2, &a2_lo, &a2_hi);
- Update2Pixels(p1, q1, &a1_lo, &a1_hi);
- Update2Pixels(p0, q0, &a0_lo, &a0_hi);
+ Update2Pixels_SSE2(p2, q2, &a2_lo, &a2_hi);
+ Update2Pixels_SSE2(p1, q1, &a1_lo, &a1_hi);
+ Update2Pixels_SSE2(p0, q0, &a0_lo, &a0_hi);
}
}
// reads 8 rows across a vertical edge.
-static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
- __m128i* const p, __m128i* const q) {
+static WEBP_INLINE void Load8x4_SSE2(const uint8_t* const b, int stride,
+ __m128i* const p, __m128i* const q) {
// A0 = 63 62 61 60 23 22 21 20 43 42 41 40 03 02 01 00
// A1 = 73 72 71 70 33 32 31 30 53 52 51 50 13 12 11 10
const __m128i A0 = _mm_set_epi32(
@@ -494,11 +499,11 @@ static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
*q = _mm_unpackhi_epi32(C0, C1);
}
-static WEBP_INLINE void Load16x4(const uint8_t* const r0,
- const uint8_t* const r8,
- int stride,
- __m128i* const p1, __m128i* const p0,
- __m128i* const q0, __m128i* const q1) {
+static WEBP_INLINE void Load16x4_SSE2(const uint8_t* const r0,
+ const uint8_t* const r8,
+ int stride,
+ __m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1) {
// Assume the pixels around the edge (|) are numbered as follows
// 00 01 | 02 03
// 10 11 | 12 13
@@ -514,8 +519,8 @@ static WEBP_INLINE void Load16x4(const uint8_t* const r0,
// q0 = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
// p0 = f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80
// q1 = f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82
- Load8x4(r0, stride, p1, q0);
- Load8x4(r8, stride, p0, q1);
+ Load8x4_SSE2(r0, stride, p1, q0);
+ Load8x4_SSE2(r8, stride, p0, q1);
{
// p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
@@ -531,7 +536,8 @@ static WEBP_INLINE void Load16x4(const uint8_t* const r0,
}
}
-static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
+static WEBP_INLINE void Store4x4_SSE2(__m128i* const x,
+ uint8_t* dst, int stride) {
int i;
for (i = 0; i < 4; ++i, dst += stride) {
WebPUint32ToMem(dst, _mm_cvtsi128_si32(*x));
@@ -540,12 +546,12 @@ static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
}
// Transpose back and store
-static WEBP_INLINE void Store16x4(const __m128i* const p1,
- const __m128i* const p0,
- const __m128i* const q0,
- const __m128i* const q1,
- uint8_t* r0, uint8_t* r8,
- int stride) {
+static WEBP_INLINE void Store16x4_SSE2(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ uint8_t* r0, uint8_t* r8,
+ int stride) {
__m128i t1, p1_s, p0_s, q0_s, q1_s;
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
@@ -572,55 +578,55 @@ static WEBP_INLINE void Store16x4(const __m128i* const p1,
p1_s = _mm_unpacklo_epi16(t1, q1_s);
q1_s = _mm_unpackhi_epi16(t1, q1_s);
- Store4x4(&p0_s, r0, stride);
+ Store4x4_SSE2(&p0_s, r0, stride);
r0 += 4 * stride;
- Store4x4(&q0_s, r0, stride);
+ Store4x4_SSE2(&q0_s, r0, stride);
- Store4x4(&p1_s, r8, stride);
+ Store4x4_SSE2(&p1_s, r8, stride);
r8 += 4 * stride;
- Store4x4(&q1_s, r8, stride);
+ Store4x4_SSE2(&q1_s, r8, stride);
}
//------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
-static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16_SSE2(uint8_t* p, int stride, int thresh) {
// Load
__m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]);
__m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]);
__m128i q0 = _mm_loadu_si128((__m128i*)&p[0]);
__m128i q1 = _mm_loadu_si128((__m128i*)&p[stride]);
- DoFilter2(&p1, &p0, &q0, &q1, thresh);
+ DoFilter2_SSE2(&p1, &p0, &q0, &q1, thresh);
// Store
_mm_storeu_si128((__m128i*)&p[-stride], p0);
_mm_storeu_si128((__m128i*)&p[0], q0);
}
-static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16_SSE2(uint8_t* p, int stride, int thresh) {
__m128i p1, p0, q0, q1;
p -= 2; // beginning of p1
- Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
- DoFilter2(&p1, &p0, &q0, &q1, thresh);
- Store16x4(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
+ Load16x4_SSE2(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ DoFilter2_SSE2(&p1, &p0, &q0, &q1, thresh);
+ Store16x4_SSE2(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
}
-static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4 * stride;
- SimpleVFilter16(p, stride, thresh);
+ SimpleVFilter16_SSE2(p, stride, thresh);
}
}
-static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16i_SSE2(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
- SimpleHFilter16(p, stride, thresh);
+ SimpleHFilter16_SSE2(p, stride, thresh);
}
}
@@ -628,60 +634,60 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
// Complex In-loop filtering (Paragraph 15.3)
#define MAX_DIFF1(p3, p2, p1, p0, m) do { \
- m = MM_ABS(p1, p0); \
- m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
- m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
+ (m) = MM_ABS(p1, p0); \
+ (m) = _mm_max_epu8(m, MM_ABS(p3, p2)); \
+ (m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
} while (0)
#define MAX_DIFF2(p3, p2, p1, p0, m) do { \
- m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
- m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
- m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
+ (m) = _mm_max_epu8(m, MM_ABS(p1, p0)); \
+ (m) = _mm_max_epu8(m, MM_ABS(p3, p2)); \
+ (m) = _mm_max_epu8(m, MM_ABS(p2, p1)); \
} while (0)
#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
- e1 = _mm_loadu_si128((__m128i*)&(p)[0 * stride]); \
- e2 = _mm_loadu_si128((__m128i*)&(p)[1 * stride]); \
- e3 = _mm_loadu_si128((__m128i*)&(p)[2 * stride]); \
- e4 = _mm_loadu_si128((__m128i*)&(p)[3 * stride]); \
+ (e1) = _mm_loadu_si128((__m128i*)&(p)[0 * (stride)]); \
+ (e2) = _mm_loadu_si128((__m128i*)&(p)[1 * (stride)]); \
+ (e3) = _mm_loadu_si128((__m128i*)&(p)[2 * (stride)]); \
+ (e4) = _mm_loadu_si128((__m128i*)&(p)[3 * (stride)]); \
}
#define LOADUV_H_EDGE(p, u, v, stride) do { \
const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
const __m128i V = _mm_loadl_epi64((__m128i*)&(v)[(stride)]); \
- p = _mm_unpacklo_epi64(U, V); \
+ (p) = _mm_unpacklo_epi64(U, V); \
} while (0)
#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
- LOADUV_H_EDGE(e1, u, v, 0 * stride); \
- LOADUV_H_EDGE(e2, u, v, 1 * stride); \
- LOADUV_H_EDGE(e3, u, v, 2 * stride); \
- LOADUV_H_EDGE(e4, u, v, 3 * stride); \
+ LOADUV_H_EDGE(e1, u, v, 0 * (stride)); \
+ LOADUV_H_EDGE(e2, u, v, 1 * (stride)); \
+ LOADUV_H_EDGE(e3, u, v, 2 * (stride)); \
+ LOADUV_H_EDGE(e4, u, v, 3 * (stride)); \
}
#define STOREUV(p, u, v, stride) { \
- _mm_storel_epi64((__m128i*)&u[(stride)], p); \
- p = _mm_srli_si128(p, 8); \
- _mm_storel_epi64((__m128i*)&v[(stride)], p); \
+ _mm_storel_epi64((__m128i*)&(u)[(stride)], p); \
+ (p) = _mm_srli_si128(p, 8); \
+ _mm_storel_epi64((__m128i*)&(v)[(stride)], p); \
}
-static WEBP_INLINE void ComplexMask(const __m128i* const p1,
- const __m128i* const p0,
- const __m128i* const q0,
- const __m128i* const q1,
- int thresh, int ithresh,
- __m128i* const mask) {
+static WEBP_INLINE void ComplexMask_SSE2(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int thresh, int ithresh,
+ __m128i* const mask) {
const __m128i it = _mm_set1_epi8(ithresh);
const __m128i diff = _mm_subs_epu8(*mask, it);
const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128());
__m128i filter_mask;
- NeedsFilter(p1, p0, q0, q1, thresh, &filter_mask);
+ NeedsFilter_SSE2(p1, p0, q0, q1, thresh, &filter_mask);
*mask = _mm_and_si128(thresh_mask, filter_mask);
}
// on macroblock edges
-static void VFilter16(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16_SSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i t1;
__m128i mask;
__m128i p2, p1, p0, q0, q1, q2;
@@ -694,8 +700,8 @@ static void VFilter16(uint8_t* p, int stride,
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
MAX_DIFF2(t1, q2, q1, q0, mask);
- ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
- DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
+ DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
// Store
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
@@ -706,28 +712,28 @@ static void VFilter16(uint8_t* p, int stride,
_mm_storeu_si128((__m128i*)&p[+2 * stride], q2);
}
-static void HFilter16(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16_SSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
uint8_t* const b = p - 4;
- Load16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0
+ Load16x4_SSE2(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0);
MAX_DIFF1(p3, p2, p1, p0, mask);
- Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
+ Load16x4_SSE2(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3);
MAX_DIFF2(q3, q2, q1, q0, mask);
- ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
- DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
+ DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
- Store16x4(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
- Store16x4(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
+ Store16x4_SSE2(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
+ Store16x4_SSE2(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
}
// on three inner edges
-static void VFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16i_SSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
__m128i p3, p2, p1, p0; // loop invariants
@@ -744,8 +750,8 @@ static void VFilter16i(uint8_t* p, int stride,
// p3 and p2 are not just temporary variables here: they will be
// re-used for next span. And q2/q3 will become p1/p0 accordingly.
- ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
- DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
+ DoFilter4_SSE2(&p1, &p0, &p3, &p2, &mask, hev_thresh);
// Store
_mm_storeu_si128((__m128i*)&b[0 * stride], p1);
@@ -759,12 +765,12 @@ static void VFilter16i(uint8_t* p, int stride,
}
}
-static void HFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16i_SSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
__m128i p3, p2, p1, p0; // loop invariants
- Load16x4(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue
+ Load16x4_SSE2(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue
for (k = 3; k > 0; --k) {
__m128i mask, tmp1, tmp2;
@@ -773,13 +779,13 @@ static void HFilter16i(uint8_t* p, int stride,
p += 4; // beginning of q0 (and next span)
MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
- Load16x4(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2);
+ Load16x4_SSE2(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2);
MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
- ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
- DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
+ DoFilter4_SSE2(&p1, &p0, &p3, &p2, &mask, hev_thresh);
- Store16x4(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride);
+ Store16x4_SSE2(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride);
// rotate samples
p1 = tmp1;
@@ -788,8 +794,8 @@ static void HFilter16i(uint8_t* p, int stride,
}
// 8-pixels wide variant, for chroma filtering
-static void VFilter8(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8_SSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, p2, p1, p0, q0, q1, q2;
@@ -801,8 +807,8 @@ static void VFilter8(uint8_t* u, uint8_t* v, int stride,
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
MAX_DIFF2(t1, q2, q1, q0, mask);
- ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
- DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
+ DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
// Store
STOREUV(p2, u, v, -3 * stride);
@@ -813,28 +819,28 @@ static void VFilter8(uint8_t* u, uint8_t* v, int stride,
STOREUV(q2, u, v, 2 * stride);
}
-static void HFilter8(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8_SSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
uint8_t* const tu = u - 4;
uint8_t* const tv = v - 4;
- Load16x4(tu, tv, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0
+ Load16x4_SSE2(tu, tv, stride, &p3, &p2, &p1, &p0);
MAX_DIFF1(p3, p2, p1, p0, mask);
- Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
+ Load16x4_SSE2(u, v, stride, &q0, &q1, &q2, &q3);
MAX_DIFF2(q3, q2, q1, q0, mask);
- ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
- DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
+ DoFilter6_SSE2(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
- Store16x4(&p3, &p2, &p1, &p0, tu, tv, stride);
- Store16x4(&q0, &q1, &q2, &q3, u, v, stride);
+ Store16x4_SSE2(&p3, &p2, &p1, &p0, tu, tv, stride);
+ Store16x4_SSE2(&q0, &q1, &q2, &q3, u, v, stride);
}
-static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, t2, p1, p0, q0, q1;
@@ -849,8 +855,8 @@ static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
MAX_DIFF2(t2, t1, q1, q0, mask);
- ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
- DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
+ DoFilter4_SSE2(&p1, &p0, &q0, &q1, &mask, hev_thresh);
// Store
STOREUV(p1, u, v, -2 * stride);
@@ -859,24 +865,24 @@ static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
STOREUV(q1, u, v, 1 * stride);
}
-static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8i_SSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, t2, p1, p0, q0, q1;
- Load16x4(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
+ Load16x4_SSE2(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
MAX_DIFF1(t2, t1, p1, p0, mask);
u += 4; // beginning of q0
v += 4;
- Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
+ Load16x4_SSE2(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
MAX_DIFF2(t2, t1, q1, q0, mask);
- ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
- DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+ ComplexMask_SSE2(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
+ DoFilter4_SSE2(&p1, &p0, &q0, &q1, &mask, hev_thresh);
u -= 2; // beginning of p1
v -= 2;
- Store16x4(&p1, &p0, &q0, &q1, u, v, stride);
+ Store16x4_SSE2(&p1, &p0, &q0, &q1, u, v, stride);
}
//------------------------------------------------------------------------------
@@ -893,7 +899,7 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1
// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1
-static void VE4(uint8_t* dst) { // vertical
+static void VE4_SSE2(uint8_t* dst) { // vertical
const __m128i one = _mm_set1_epi8(1);
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
@@ -909,7 +915,7 @@ static void VE4(uint8_t* dst) { // vertical
}
}
-static void LD4(uint8_t* dst) { // Down-Left
+static void LD4_SSE2(uint8_t* dst) { // Down-Left
const __m128i one = _mm_set1_epi8(1);
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
@@ -925,7 +931,7 @@ static void LD4(uint8_t* dst) { // Down-Left
WebPUint32ToMem(dst + 3 * BPS, _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3)));
}
-static void VR4(uint8_t* dst) { // Vertical-Right
+static void VR4_SSE2(uint8_t* dst) { // Vertical-Right
const __m128i one = _mm_set1_epi8(1);
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
@@ -950,7 +956,7 @@ static void VR4(uint8_t* dst) { // Vertical-Right
DST(0, 3) = AVG3(K, J, I);
}
-static void VL4(uint8_t* dst) { // Vertical-Left
+static void VL4_SSE2(uint8_t* dst) { // Vertical-Left
const __m128i one = _mm_set1_epi8(1);
const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1);
@@ -975,7 +981,7 @@ static void VL4(uint8_t* dst) { // Vertical-Left
DST(3, 3) = (extra_out >> 8) & 0xff;
}
-static void RD4(uint8_t* dst) { // Down-right
+static void RD4_SSE2(uint8_t* dst) { // Down-right
const __m128i one = _mm_set1_epi8(1);
const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
const __m128i ____XABCD = _mm_slli_si128(XABCD, 4);
@@ -1004,7 +1010,7 @@ static void RD4(uint8_t* dst) { // Down-right
//------------------------------------------------------------------------------
// Luma 16x16
-static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
+static WEBP_INLINE void TrueMotion_SSE2(uint8_t* dst, int size) {
const uint8_t* top = dst - BPS;
const __m128i zero = _mm_setzero_si128();
int y;
@@ -1041,11 +1047,11 @@ static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
}
}
-static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
-static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
-static void TM16(uint8_t* dst) { TrueMotion(dst, 16); }
+static void TM4_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 4); }
+static void TM8uv_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 8); }
+static void TM16_SSE2(uint8_t* dst) { TrueMotion_SSE2(dst, 16); }
-static void VE16(uint8_t* dst) {
+static void VE16_SSE2(uint8_t* dst) {
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
int j;
for (j = 0; j < 16; ++j) {
@@ -1053,7 +1059,7 @@ static void VE16(uint8_t* dst) {
}
}
-static void HE16(uint8_t* dst) { // horizontal
+static void HE16_SSE2(uint8_t* dst) { // horizontal
int j;
for (j = 16; j > 0; --j) {
const __m128i values = _mm_set1_epi8(dst[-1]);
@@ -1062,7 +1068,7 @@ static void HE16(uint8_t* dst) { // horizontal
}
}
-static WEBP_INLINE void Put16(uint8_t v, uint8_t* dst) {
+static WEBP_INLINE void Put16_SSE2(uint8_t v, uint8_t* dst) {
int j;
const __m128i values = _mm_set1_epi8(v);
for (j = 0; j < 16; ++j) {
@@ -1070,7 +1076,7 @@ static WEBP_INLINE void Put16(uint8_t v, uint8_t* dst) {
}
}
-static void DC16(uint8_t* dst) { // DC
+static void DC16_SSE2(uint8_t* dst) { // DC
const __m128i zero = _mm_setzero_si128();
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
const __m128i sad8x2 = _mm_sad_epu8(top, zero);
@@ -1083,37 +1089,37 @@ static void DC16(uint8_t* dst) { // DC
}
{
const int DC = _mm_cvtsi128_si32(sum) + left + 16;
- Put16(DC >> 5, dst);
+ Put16_SSE2(DC >> 5, dst);
}
}
-static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
+static void DC16NoTop_SSE2(uint8_t* dst) { // DC with top samples unavailable
int DC = 8;
int j;
for (j = 0; j < 16; ++j) {
DC += dst[-1 + j * BPS];
}
- Put16(DC >> 4, dst);
+ Put16_SSE2(DC >> 4, dst);
}
-static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
+static void DC16NoLeft_SSE2(uint8_t* dst) { // DC with left samples unavailable
const __m128i zero = _mm_setzero_si128();
const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
const __m128i sad8x2 = _mm_sad_epu8(top, zero);
// sum the two sads: sad8x2[0:1] + sad8x2[8:9]
const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
const int DC = _mm_cvtsi128_si32(sum) + 8;
- Put16(DC >> 4, dst);
+ Put16_SSE2(DC >> 4, dst);
}
-static void DC16NoTopLeft(uint8_t* dst) { // DC with no top and left samples
- Put16(0x80, dst);
+static void DC16NoTopLeft_SSE2(uint8_t* dst) { // DC with no top & left samples
+ Put16_SSE2(0x80, dst);
}
//------------------------------------------------------------------------------
// Chroma
-static void VE8uv(uint8_t* dst) { // vertical
+static void VE8uv_SSE2(uint8_t* dst) { // vertical
int j;
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
for (j = 0; j < 8; ++j) {
@@ -1121,17 +1127,8 @@ static void VE8uv(uint8_t* dst) { // vertical
}
}
-static void HE8uv(uint8_t* dst) { // horizontal
- int j;
- for (j = 0; j < 8; ++j) {
- const __m128i values = _mm_set1_epi8(dst[-1]);
- _mm_storel_epi64((__m128i*)dst, values);
- dst += BPS;
- }
-}
-
// helper for chroma-DC predictions
-static WEBP_INLINE void Put8x8uv(uint8_t v, uint8_t* dst) {
+static WEBP_INLINE void Put8x8uv_SSE2(uint8_t v, uint8_t* dst) {
int j;
const __m128i values = _mm_set1_epi8(v);
for (j = 0; j < 8; ++j) {
@@ -1139,7 +1136,7 @@ static WEBP_INLINE void Put8x8uv(uint8_t v, uint8_t* dst) {
}
}
-static void DC8uv(uint8_t* dst) { // DC
+static void DC8uv_SSE2(uint8_t* dst) { // DC
const __m128i zero = _mm_setzero_si128();
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
const __m128i sum = _mm_sad_epu8(top, zero);
@@ -1150,29 +1147,29 @@ static void DC8uv(uint8_t* dst) { // DC
}
{
const int DC = _mm_cvtsi128_si32(sum) + left + 8;
- Put8x8uv(DC >> 4, dst);
+ Put8x8uv_SSE2(DC >> 4, dst);
}
}
-static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
+static void DC8uvNoLeft_SSE2(uint8_t* dst) { // DC with no left samples
const __m128i zero = _mm_setzero_si128();
const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
const __m128i sum = _mm_sad_epu8(top, zero);
const int DC = _mm_cvtsi128_si32(sum) + 4;
- Put8x8uv(DC >> 3, dst);
+ Put8x8uv_SSE2(DC >> 3, dst);
}
-static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
+static void DC8uvNoTop_SSE2(uint8_t* dst) { // DC with no top samples
int dc0 = 4;
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[-1 + i * BPS];
}
- Put8x8uv(dc0 >> 3, dst);
+ Put8x8uv_SSE2(dc0 >> 3, dst);
}
-static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
- Put8x8uv(0x80, dst);
+static void DC8uvNoTopLeft_SSE2(uint8_t* dst) { // DC with nothing
+ Put8x8uv_SSE2(0x80, dst);
}
//------------------------------------------------------------------------------
@@ -1181,47 +1178,46 @@ static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
extern void VP8DspInitSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE2(void) {
- VP8Transform = Transform;
-#if defined(USE_TRANSFORM_AC3)
- VP8TransformAC3 = TransformAC3;
+ VP8Transform = Transform_SSE2;
+#if (USE_TRANSFORM_AC3 == 1)
+ VP8TransformAC3 = TransformAC3_SSE2;
#endif
- VP8VFilter16 = VFilter16;
- VP8HFilter16 = HFilter16;
- VP8VFilter8 = VFilter8;
- VP8HFilter8 = HFilter8;
- VP8VFilter16i = VFilter16i;
- VP8HFilter16i = HFilter16i;
- VP8VFilter8i = VFilter8i;
- VP8HFilter8i = HFilter8i;
-
- VP8SimpleVFilter16 = SimpleVFilter16;
- VP8SimpleHFilter16 = SimpleHFilter16;
- VP8SimpleVFilter16i = SimpleVFilter16i;
- VP8SimpleHFilter16i = SimpleHFilter16i;
-
- VP8PredLuma4[1] = TM4;
- VP8PredLuma4[2] = VE4;
- VP8PredLuma4[4] = RD4;
- VP8PredLuma4[5] = VR4;
- VP8PredLuma4[6] = LD4;
- VP8PredLuma4[7] = VL4;
-
- VP8PredLuma16[0] = DC16;
- VP8PredLuma16[1] = TM16;
- VP8PredLuma16[2] = VE16;
- VP8PredLuma16[3] = HE16;
- VP8PredLuma16[4] = DC16NoTop;
- VP8PredLuma16[5] = DC16NoLeft;
- VP8PredLuma16[6] = DC16NoTopLeft;
-
- VP8PredChroma8[0] = DC8uv;
- VP8PredChroma8[1] = TM8uv;
- VP8PredChroma8[2] = VE8uv;
- VP8PredChroma8[3] = HE8uv;
- VP8PredChroma8[4] = DC8uvNoTop;
- VP8PredChroma8[5] = DC8uvNoLeft;
- VP8PredChroma8[6] = DC8uvNoTopLeft;
+ VP8VFilter16 = VFilter16_SSE2;
+ VP8HFilter16 = HFilter16_SSE2;
+ VP8VFilter8 = VFilter8_SSE2;
+ VP8HFilter8 = HFilter8_SSE2;
+ VP8VFilter16i = VFilter16i_SSE2;
+ VP8HFilter16i = HFilter16i_SSE2;
+ VP8VFilter8i = VFilter8i_SSE2;
+ VP8HFilter8i = HFilter8i_SSE2;
+
+ VP8SimpleVFilter16 = SimpleVFilter16_SSE2;
+ VP8SimpleHFilter16 = SimpleHFilter16_SSE2;
+ VP8SimpleVFilter16i = SimpleVFilter16i_SSE2;
+ VP8SimpleHFilter16i = SimpleHFilter16i_SSE2;
+
+ VP8PredLuma4[1] = TM4_SSE2;
+ VP8PredLuma4[2] = VE4_SSE2;
+ VP8PredLuma4[4] = RD4_SSE2;
+ VP8PredLuma4[5] = VR4_SSE2;
+ VP8PredLuma4[6] = LD4_SSE2;
+ VP8PredLuma4[7] = VL4_SSE2;
+
+ VP8PredLuma16[0] = DC16_SSE2;
+ VP8PredLuma16[1] = TM16_SSE2;
+ VP8PredLuma16[2] = VE16_SSE2;
+ VP8PredLuma16[3] = HE16_SSE2;
+ VP8PredLuma16[4] = DC16NoTop_SSE2;
+ VP8PredLuma16[5] = DC16NoLeft_SSE2;
+ VP8PredLuma16[6] = DC16NoTopLeft_SSE2;
+
+ VP8PredChroma8[0] = DC8uv_SSE2;
+ VP8PredChroma8[1] = TM8uv_SSE2;
+ VP8PredChroma8[2] = VE8uv_SSE2;
+ VP8PredChroma8[4] = DC8uvNoTop_SSE2;
+ VP8PredChroma8[5] = DC8uvNoLeft_SSE2;
+ VP8PredChroma8[6] = DC8uvNoTopLeft_SSE2;
}
#else // !WEBP_USE_SSE2
diff --git a/media/libwebp/dsp/dec_sse41.c b/media/libwebp/dsp/dec_sse41.c
index 4e81ec4d8..02deae956 100644
--- a/media/libwebp/dsp/dec_sse41.c
+++ b/media/libwebp/dsp/dec_sse41.c
@@ -11,7 +11,7 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE41)
@@ -19,7 +19,7 @@
#include "../dec/vp8i_dec.h"
#include "../utils/utils.h"
-static void HE16(uint8_t* dst) { // horizontal
+static void HE16_SSE41(uint8_t* dst) { // horizontal
int j;
const __m128i kShuffle3 = _mm_set1_epi8(3);
for (j = 16; j > 0; --j) {
@@ -36,7 +36,7 @@ static void HE16(uint8_t* dst) { // horizontal
extern void VP8DspInitSSE41(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE41(void) {
- VP8PredLuma16[3] = HE16;
+ VP8PredLuma16[3] = HE16_SSE41;
}
#else // !WEBP_USE_SSE41
diff --git a/media/libwebp/dsp/dsp.h b/media/libwebp/dsp/dsp.h
index 813fed4a3..537ea2044 100644
--- a/media/libwebp/dsp/dsp.h
+++ b/media/libwebp/dsp/dsp.h
@@ -38,10 +38,22 @@ extern "C" {
# define LOCAL_GCC_PREREQ(maj, min) 0
#endif
+#if defined(__clang__)
+# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
+# define LOCAL_CLANG_PREREQ(maj, min) \
+ (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
+#else
+# define LOCAL_CLANG_VERSION 0
+# define LOCAL_CLANG_PREREQ(maj, min) 0
+#endif
+
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
+// for now, none of the optimizations below are available in emscripten
+#if !defined(EMSCRIPTEN)
+
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
@@ -68,18 +80,20 @@ extern "C" {
#define WEBP_USE_AVX2
#endif
-#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
-#define WEBP_ANDROID_NEON // Android targets that might support NEON
-#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__) || defined(WEBP_ANDROID_NEON) || \
+#if (defined(__ARM_NEON__) || \
defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
!defined(__native_client__)
#define WEBP_USE_NEON
#endif
+#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
+ defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
+#define WEBP_ANDROID_NEON // Android targets that may have NEON
+#define WEBP_USE_NEON
+#endif
+
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
#define WEBP_USE_NEON
#define WEBP_USE_INTRINSICS
@@ -90,7 +104,7 @@ extern "C" {
#define WEBP_USE_MIPS32
#if (__mips_isa_rev >= 2)
#define WEBP_USE_MIPS32_R2
-#if defined(__mips_dspr2) || (__mips_dsp_rev >= 2)
+#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
#define WEBP_USE_MIPS_DSP_R2
#endif
#endif
@@ -100,6 +114,24 @@ extern "C" {
#define WEBP_USE_MSA
#endif
+#endif /* EMSCRIPTEN */
+
+#ifndef WEBP_DSP_OMIT_C_CODE
+#define WEBP_DSP_OMIT_C_CODE 1
+#endif
+
+#if (defined(__aarch64__) || defined(__ARM_NEON__)) && WEBP_DSP_OMIT_C_CODE
+#define WEBP_NEON_OMIT_C_CODE 1
+#else
+#define WEBP_NEON_OMIT_C_CODE 0
+#endif
+
+#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
+#define WEBP_NEON_WORK_AROUND_GCC 1
+#else
+#define WEBP_NEON_WORK_AROUND_GCC 0
+#endif
+
// This macro prevents thread_sanitizer from reporting known concurrent writes.
#define WEBP_TSAN_IGNORE_FUNCTION
#if defined(__has_feature)
@@ -109,6 +141,42 @@ extern "C" {
#endif
#endif
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+#include <pthread.h> // NOLINT
+
+#define WEBP_DSP_INIT(func) do { \
+ static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
+ (VP8CPUInfo)&func ## _last_cpuinfo_used; \
+ static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \
+ if (pthread_mutex_lock(&func ## _lock)) break; \
+ if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \
+ func ## _last_cpuinfo_used = VP8GetCPUInfo; \
+ (void)pthread_mutex_unlock(&func ## _lock); \
+} while (0)
+#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
+#define WEBP_DSP_INIT(func) do { \
+ static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
+ (VP8CPUInfo)&func ## _last_cpuinfo_used; \
+ if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \
+ func(); \
+ func ## _last_cpuinfo_used = VP8GetCPUInfo; \
+} while (0)
+#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
+
+// Defines an Init + helper function that control multiple initialization of
+// function pointers / tables.
+/* Usage:
+ WEBP_DSP_INIT_FUNC(InitFunc) {
+ ...function body
+ }
+*/
+#define WEBP_DSP_INIT_FUNC(name) \
+ static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \
+ WEBP_TSAN_IGNORE_FUNCTION void name(void) { \
+ WEBP_DSP_INIT(name ## _body); \
+ } \
+ static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void)
+
#define WEBP_UBSAN_IGNORE_UNDEF
#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
#if defined(__clang__) && defined(__has_attribute)
@@ -129,6 +197,18 @@ extern "C" {
#endif
#endif
+// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
+#if !defined(WEBP_SWAP_16BIT_CSP)
+#define WEBP_SWAP_16BIT_CSP 0
+#endif
+
+// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
+#if !defined(WORDS_BIGENDIAN) && \
+ (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
+#define WORDS_BIGENDIAN
+#endif
+
typedef enum {
kSSE2,
kSSE3,
@@ -143,7 +223,7 @@ typedef enum {
} CPUFeature;
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);
-WEBP_EXTERN(VP8CPUInfo) VP8GetCPUInfo;
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
//------------------------------------------------------------------------------
// Init stub generator
@@ -152,7 +232,7 @@ WEBP_EXTERN(VP8CPUInfo) VP8GetCPUInfo;
// avoiding a compiler warning.
#define WEBP_DSP_INIT_STUB(func) \
extern void func(void); \
- WEBP_TSAN_IGNORE_FUNCTION void func(void) {}
+ void func(void) {}
//------------------------------------------------------------------------------
// Encoding
@@ -271,6 +351,7 @@ typedef double (*VP8SSIMGetClippedFunc)(const uint8_t* src1, int stride1,
int xo, int yo, // center position
int W, int H); // plane dimension
+#if !defined(WEBP_REDUCE_SIZE)
// This version is called with the guarantee that you can load 8 bytes and
// 8 rows at offset src1 and src2
typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1,
@@ -278,10 +359,13 @@ typedef double (*VP8SSIMGetFunc)(const uint8_t* src1, int stride1,
extern VP8SSIMGetFunc VP8SSIMGet; // unclipped / unchecked
extern VP8SSIMGetClippedFunc VP8SSIMGetClipped; // with clipping
+#endif
+#if !defined(WEBP_DISABLE_STATS)
typedef uint32_t (*VP8AccumulateSSEFunc)(const uint8_t* src1,
const uint8_t* src2, int len);
extern VP8AccumulateSSEFunc VP8AccumulateSSE;
+#endif
// must be called before using any of the above directly
void VP8SSIMDspInit(void);
@@ -462,12 +546,12 @@ extern WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
extern WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
// Plain-C implementation, as fall-back.
-extern void WebPRescalerImportRowExpandC(struct WebPRescaler* const wrk,
- const uint8_t* src);
-extern void WebPRescalerImportRowShrinkC(struct WebPRescaler* const wrk,
- const uint8_t* src);
-extern void WebPRescalerExportRowExpandC(struct WebPRescaler* const wrk);
-extern void WebPRescalerExportRowShrinkC(struct WebPRescaler* const wrk);
+extern void WebPRescalerImportRowExpand_C(struct WebPRescaler* const wrk,
+ const uint8_t* src);
+extern void WebPRescalerImportRowShrink_C(struct WebPRescaler* const wrk,
+ const uint8_t* src);
+extern void WebPRescalerExportRowExpand_C(struct WebPRescaler* const wrk);
+extern void WebPRescalerExportRowShrink_C(struct WebPRescaler* const wrk);
// Main entry calls:
extern void WebPRescalerImportRow(struct WebPRescaler* const wrk,
@@ -533,24 +617,28 @@ void WebPMultRows(uint8_t* ptr, int stride,
int width, int num_rows, int inverse);
// Plain-C versions, used as fallback by some implementations.
-void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
- int width, int inverse);
-void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse);
-
-// To be called first before using the above.
-void WebPInitAlphaProcessing(void);
+void WebPMultRow_C(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse);
+void WebPMultARGBRow_C(uint32_t* const ptr, int width, int inverse);
+#ifdef WORDS_BIGENDIAN
// ARGB packing function: a/r/g/b input is rgba or bgra order.
-extern void (*VP8PackARGB)(const uint8_t* a, const uint8_t* r,
- const uint8_t* g, const uint8_t* b, int len,
- uint32_t* out);
+extern void (*WebPPackARGB)(const uint8_t* a, const uint8_t* r,
+ const uint8_t* g, const uint8_t* b, int len,
+ uint32_t* out);
+#endif
// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
-extern void (*VP8PackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
- int len, int step, uint32_t* out);
+extern void (*WebPPackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
+ int len, int step, uint32_t* out);
+
+// This function returns true if src[i] contains a value different from 0xff.
+extern int (*WebPHasAlpha8b)(const uint8_t* src, int length);
+// This function returns true if src[4*i] contains a value different from 0xff.
+extern int (*WebPHasAlpha32b)(const uint8_t* src, int length);
// To be called first before using the above.
-void VP8EncDspARGBInit(void);
+void WebPInitAlphaProcessing(void);
//------------------------------------------------------------------------------
// Filter functions
diff --git a/media/libwebp/dsp/filters.c b/media/libwebp/dsp/filters.c
index 65f34aad1..dea3eb410 100644
--- a/media/libwebp/dsp/filters.c
+++ b/media/libwebp/dsp/filters.c
@@ -11,7 +11,7 @@
//
// Author: Urvang (urvang@google.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -20,16 +20,17 @@
// Helpful macro.
# define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
+ assert((in) != NULL); \
+ assert((out) != NULL); \
assert(width > 0); \
assert(height > 0); \
assert(stride >= width); \
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
(void)height; // Silence unused warning.
-static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
- uint8_t* dst, int length, int inverse) {
+#if !WEBP_NEON_OMIT_C_CODE
+static WEBP_INLINE void PredictLine_C(const uint8_t* src, const uint8_t* pred,
+ uint8_t* dst, int length, int inverse) {
int i;
if (inverse) {
for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
@@ -41,10 +42,10 @@ static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
//------------------------------------------------------------------------------
// Horizontal filter.
-static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
+static WEBP_INLINE void DoHorizontalFilter_C(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
@@ -56,7 +57,7 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
if (row == 0) {
// Leftmost pixel is the same as input for topmost scanline.
out[0] = in[0];
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
row = 1;
preds += stride;
in += stride;
@@ -66,8 +67,8 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
// Filter line-by-line.
while (row < last_row) {
// Leftmost pixel is predicted from above.
- PredictLine(in, preds - stride, out, 1, inverse);
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ PredictLine_C(in, preds - stride, out, 1, inverse);
+ PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
++row;
preds += stride;
in += stride;
@@ -78,10 +79,10 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
//------------------------------------------------------------------------------
// Vertical filter.
-static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
+static WEBP_INLINE void DoVerticalFilter_C(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
@@ -94,7 +95,7 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
// Very first top-left pixel is copied.
out[0] = in[0];
// Rest of top scan-line is left-predicted.
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
row = 1;
in += stride;
out += stride;
@@ -105,26 +106,28 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
// Filter line-by-line.
while (row < last_row) {
- PredictLine(in, preds, out, width, inverse);
+ PredictLine_C(in, preds, out, width, inverse);
++row;
preds += stride;
in += stride;
out += stride;
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
//------------------------------------------------------------------------------
// Gradient filter.
-static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
+static WEBP_INLINE int GradientPredictor_C(uint8_t a, uint8_t b, uint8_t c) {
const int g = a + b - c;
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
}
-static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
+#if !WEBP_NEON_OMIT_C_CODE
+static WEBP_INLINE void DoGradientFilter_C(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
const uint8_t* preds;
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
@@ -136,7 +139,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
// left prediction for top scan-line
if (row == 0) {
out[0] = in[0];
- PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ PredictLine_C(in + 1, preds, out + 1, width - 1, inverse);
row = 1;
preds += stride;
in += stride;
@@ -147,11 +150,11 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
while (row < last_row) {
int w;
// leftmost pixel: predict from above.
- PredictLine(in, preds - stride, out, 1, inverse);
+ PredictLine_C(in, preds - stride, out, 1, inverse);
for (w = 1; w < width; ++w) {
- const int pred = GradientPredictor(preds[w - 1],
- preds[w - stride],
- preds[w - stride - 1]);
+ const int pred = GradientPredictor_C(preds[w - 1],
+ preds[w - stride],
+ preds[w - stride - 1]);
out[w] = in[w] + (inverse ? pred : -pred);
}
++row;
@@ -160,32 +163,34 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
out += stride;
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
#undef SANITY_CHECK
//------------------------------------------------------------------------------
-static void HorizontalFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+#if !WEBP_NEON_OMIT_C_CODE
+static void HorizontalFilter_C(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoHorizontalFilter_C(data, width, height, stride, 0, height, 0,
+ filtered_data);
}
-static void VerticalFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+static void VerticalFilter_C(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoVerticalFilter_C(data, width, height, stride, 0, height, 0, filtered_data);
}
-
-static void GradientFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
+static void GradientFilter_C(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoGradientFilter_C(data, width, height, stride, 0, height, 0, filtered_data);
}
-
+#endif // !WEBP_NEON_OMIT_C_CODE
//------------------------------------------------------------------------------
-static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
- uint8_t* out, int width) {
+static void HorizontalUnfilter_C(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
uint8_t pred = (prev == NULL) ? 0 : prev[0];
int i;
for (i = 0; i < width; ++i) {
@@ -194,26 +199,28 @@ static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
}
}
-static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
- uint8_t* out, int width) {
+#if !WEBP_NEON_OMIT_C_CODE
+static void VerticalUnfilter_C(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
if (prev == NULL) {
- HorizontalUnfilter(NULL, in, out, width);
+ HorizontalUnfilter_C(NULL, in, out, width);
} else {
int i;
for (i = 0; i < width; ++i) out[i] = prev[i] + in[i];
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
-static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
- uint8_t* out, int width) {
+static void GradientUnfilter_C(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
if (prev == NULL) {
- HorizontalUnfilter(NULL, in, out, width);
+ HorizontalUnfilter_C(NULL, in, out, width);
} else {
uint8_t top = prev[0], top_left = top, left = top;
int i;
for (i = 0; i < width; ++i) {
top = prev[i]; // need to read this first, in case prev==out
- left = in[i] + GradientPredictor(left, top, top_left);
+ left = in[i] + GradientPredictor_C(left, top, top_left);
top_left = top;
out[i] = left;
}
@@ -231,21 +238,20 @@ extern void VP8FiltersInitMSA(void);
extern void VP8FiltersInitNEON(void);
extern void VP8FiltersInitSSE2(void);
-static volatile VP8CPUInfo filters_last_cpuinfo_used =
- (VP8CPUInfo)&filters_last_cpuinfo_used;
-
-WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
- if (filters_last_cpuinfo_used == VP8GetCPUInfo) return;
-
+WEBP_DSP_INIT_FUNC(VP8FiltersInit) {
WebPUnfilters[WEBP_FILTER_NONE] = NULL;
- WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
- WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
- WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
+#if !WEBP_NEON_OMIT_C_CODE
+ WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_C;
+ WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_C;
+#endif
+ WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_C;
WebPFilters[WEBP_FILTER_NONE] = NULL;
- WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
- WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
- WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
+#if !WEBP_NEON_OMIT_C_CODE
+ WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_C;
+ WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_C;
+ WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_C;
+#endif
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
@@ -253,11 +259,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
VP8FiltersInitSSE2();
}
#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- VP8FiltersInitNEON();
- }
-#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
if (VP8GetCPUInfo(kMIPSdspR2)) {
VP8FiltersInitMIPSdspR2();
@@ -269,5 +270,18 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
}
#endif
}
- filters_last_cpuinfo_used = VP8GetCPUInfo;
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ VP8FiltersInitNEON();
+ }
+#endif
+
+ assert(WebPUnfilters[WEBP_FILTER_HORIZONTAL] != NULL);
+ assert(WebPUnfilters[WEBP_FILTER_VERTICAL] != NULL);
+ assert(WebPUnfilters[WEBP_FILTER_GRADIENT] != NULL);
+ assert(WebPFilters[WEBP_FILTER_HORIZONTAL] != NULL);
+ assert(WebPFilters[WEBP_FILTER_VERTICAL] != NULL);
+ assert(WebPFilters[WEBP_FILTER_GRADIENT] != NULL);
}
diff --git a/media/libwebp/dsp/filters_sse2.c b/media/libwebp/dsp/filters_sse2.c
index 67f77999e..2cc9bb976 100644
--- a/media/libwebp/dsp/filters_sse2.c
+++ b/media/libwebp/dsp/filters_sse2.c
@@ -11,7 +11,7 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE2)
@@ -24,16 +24,16 @@
// Helpful macro.
# define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
+ assert((in) != NULL); \
+ assert((out) != NULL); \
assert(width > 0); \
assert(height > 0); \
assert(stride >= width); \
assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
(void)height; // Silence unused warning.
-static void PredictLineTop(const uint8_t* src, const uint8_t* pred,
- uint8_t* dst, int length) {
+static void PredictLineTop_SSE2(const uint8_t* src, const uint8_t* pred,
+ uint8_t* dst, int length) {
int i;
const int max_pos = length & ~31;
assert(length >= 0);
@@ -51,7 +51,7 @@ static void PredictLineTop(const uint8_t* src, const uint8_t* pred,
}
// Special case for left-based prediction (when preds==dst-1 or preds==src-1).
-static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length) {
+static void PredictLineLeft_SSE2(const uint8_t* src, uint8_t* dst, int length) {
int i;
const int max_pos = length & ~31;
assert(length >= 0);
@@ -71,10 +71,11 @@ static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length) {
//------------------------------------------------------------------------------
// Horizontal filter.
-static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- uint8_t* out) {
+static WEBP_INLINE void DoHorizontalFilter_SSE2(const uint8_t* in,
+ int width, int height,
+ int stride,
+ int row, int num_rows,
+ uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
SANITY_CHECK(in, out);
@@ -84,7 +85,7 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
if (row == 0) {
// Leftmost pixel is the same as input for topmost scanline.
out[0] = in[0];
- PredictLineLeft(in + 1, out + 1, width - 1);
+ PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
row = 1;
in += stride;
out += stride;
@@ -94,7 +95,7 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
while (row < last_row) {
// Leftmost pixel is predicted from above.
out[0] = in[0] - in[-stride];
- PredictLineLeft(in + 1, out + 1, width - 1);
+ PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
++row;
in += stride;
out += stride;
@@ -104,9 +105,10 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
//------------------------------------------------------------------------------
// Vertical filter.
-static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows, uint8_t* out) {
+static WEBP_INLINE void DoVerticalFilter_SSE2(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
SANITY_CHECK(in, out);
@@ -117,7 +119,7 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
// Very first top-left pixel is copied.
out[0] = in[0];
// Rest of top scan-line is left-predicted.
- PredictLineLeft(in + 1, out + 1, width - 1);
+ PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
row = 1;
in += stride;
out += stride;
@@ -125,7 +127,7 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
// Filter line-by-line.
while (row < last_row) {
- PredictLineTop(in, in - stride, out, width);
+ PredictLineTop_SSE2(in, in - stride, out, width);
++row;
in += stride;
out += stride;
@@ -135,14 +137,14 @@ static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
//------------------------------------------------------------------------------
// Gradient filter.
-static WEBP_INLINE int GradientPredictorC(uint8_t a, uint8_t b, uint8_t c) {
+static WEBP_INLINE int GradientPredictor_SSE2(uint8_t a, uint8_t b, uint8_t c) {
const int g = a + b - c;
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
}
-static void GradientPredictDirect(const uint8_t* const row,
- const uint8_t* const top,
- uint8_t* const out, int length) {
+static void GradientPredictDirect_SSE2(const uint8_t* const row,
+ const uint8_t* const top,
+ uint8_t* const out, int length) {
const int max_pos = length & ~7;
int i;
const __m128i zero = _mm_setzero_si128();
@@ -161,14 +163,14 @@ static void GradientPredictDirect(const uint8_t* const row,
_mm_storel_epi64((__m128i*)(out + i), H);
}
for (; i < length; ++i) {
- out[i] = row[i] - GradientPredictorC(row[i - 1], top[i], top[i - 1]);
+ out[i] = row[i] - GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
}
}
-static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
- int width, int height, int stride,
- int row, int num_rows,
- uint8_t* out) {
+static WEBP_INLINE void DoGradientFilter_SSE2(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
SANITY_CHECK(in, out);
@@ -178,7 +180,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
// left prediction for top scan-line
if (row == 0) {
out[0] = in[0];
- PredictLineLeft(in + 1, out + 1, width - 1);
+ PredictLineLeft_SSE2(in + 1, out + 1, width - 1);
row = 1;
in += stride;
out += stride;
@@ -187,7 +189,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
// Filter line-by-line.
while (row < last_row) {
out[0] = in[0] - in[-stride];
- GradientPredictDirect(in + 1, in + 1 - stride, out + 1, width - 1);
+ GradientPredictDirect_SSE2(in + 1, in + 1 - stride, out + 1, width - 1);
++row;
in += stride;
out += stride;
@@ -198,26 +200,27 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
//------------------------------------------------------------------------------
-static void HorizontalFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoHorizontalFilter(data, width, height, stride, 0, height, filtered_data);
+static void HorizontalFilter_SSE2(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoHorizontalFilter_SSE2(data, width, height, stride, 0, height,
+ filtered_data);
}
-static void VerticalFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoVerticalFilter(data, width, height, stride, 0, height, filtered_data);
+static void VerticalFilter_SSE2(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoVerticalFilter_SSE2(data, width, height, stride, 0, height, filtered_data);
}
-static void GradientFilter(const uint8_t* data, int width, int height,
- int stride, uint8_t* filtered_data) {
- DoGradientFilter(data, width, height, stride, 0, height, filtered_data);
+static void GradientFilter_SSE2(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoGradientFilter_SSE2(data, width, height, stride, 0, height, filtered_data);
}
//------------------------------------------------------------------------------
// Inverse transforms
-static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
- uint8_t* out, int width) {
+static void HorizontalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
int i;
__m128i last;
out[0] = in[0] + (prev == NULL ? 0 : prev[0]);
@@ -238,10 +241,10 @@ static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
for (; i < width; ++i) out[i] = in[i] + out[i - 1];
}
-static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
- uint8_t* out, int width) {
+static void VerticalUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
if (prev == NULL) {
- HorizontalUnfilter(NULL, in, out, width);
+ HorizontalUnfilter_SSE2(NULL, in, out, width);
} else {
int i;
const int max_pos = width & ~31;
@@ -260,9 +263,9 @@ static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
}
}
-static void GradientPredictInverse(const uint8_t* const in,
- const uint8_t* const top,
- uint8_t* const row, int length) {
+static void GradientPredictInverse_SSE2(const uint8_t* const in,
+ const uint8_t* const top,
+ uint8_t* const row, int length) {
if (length > 0) {
int i;
const int max_pos = length & ~7;
@@ -293,18 +296,18 @@ static void GradientPredictInverse(const uint8_t* const in,
_mm_storel_epi64((__m128i*)&row[i], out);
}
for (; i < length; ++i) {
- row[i] = in[i] + GradientPredictorC(row[i - 1], top[i], top[i - 1]);
+ row[i] = in[i] + GradientPredictor_SSE2(row[i - 1], top[i], top[i - 1]);
}
}
}
-static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
- uint8_t* out, int width) {
+static void GradientUnfilter_SSE2(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
if (prev == NULL) {
- HorizontalUnfilter(NULL, in, out, width);
+ HorizontalUnfilter_SSE2(NULL, in, out, width);
} else {
out[0] = in[0] + prev[0]; // predict from above
- GradientPredictInverse(in + 1, prev + 1, out + 1, width - 1);
+ GradientPredictInverse_SSE2(in + 1, prev + 1, out + 1, width - 1);
}
}
@@ -314,13 +317,13 @@ static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
extern void VP8FiltersInitSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
- WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
- WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
- WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
+ WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter_SSE2;
+ WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter_SSE2;
+ WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter_SSE2;
- WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
- WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
- WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
+ WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter_SSE2;
+ WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter_SSE2;
+ WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter_SSE2;
}
#else // !WEBP_USE_SSE2
diff --git a/media/libwebp/dsp/lossless.c b/media/libwebp/dsp/lossless.c
index 20d18f6ec..93ccecdfd 100644
--- a/media/libwebp/dsp/lossless.c
+++ b/media/libwebp/dsp/lossless.c
@@ -13,14 +13,15 @@
// Jyrki Alakuijala (jyrki@google.com)
// Urvang Joshi (urvang@google.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
+#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "../dec/vp8li_dec.h"
#include "../utils/endian_inl_utils.h"
-#include "./lossless.h"
-#include "./lossless_common.h"
+#include "../dsp/lossless.h"
+#include "../dsp/lossless_common.h"
#define MAX_DIFF_COST (1e30f)
@@ -80,8 +81,9 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
}
-// gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined.
-#if defined(__arm__) && LOCAL_GCC_VERSION == 0x409
+// gcc <= 4.9 on ARM generates incorrect code in Select() when Sub3() is
+// inlined.
+#if defined(__arm__) && LOCAL_GCC_VERSION <= 0x409
# define LOCAL_INLINE __attribute__ ((noinline))
#else
# define LOCAL_INLINE WEBP_INLINE
@@ -107,69 +109,69 @@ static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
//------------------------------------------------------------------------------
// Predictors
-static uint32_t Predictor0(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor0_C(uint32_t left, const uint32_t* const top) {
(void)top;
(void)left;
return ARGB_BLACK;
}
-static uint32_t Predictor1(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor1_C(uint32_t left, const uint32_t* const top) {
(void)top;
return left;
}
-static uint32_t Predictor2(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor2_C(uint32_t left, const uint32_t* const top) {
(void)left;
return top[0];
}
-static uint32_t Predictor3(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor3_C(uint32_t left, const uint32_t* const top) {
(void)left;
return top[1];
}
-static uint32_t Predictor4(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor4_C(uint32_t left, const uint32_t* const top) {
(void)left;
return top[-1];
}
-static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor5_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average3(left, top[0], top[1]);
return pred;
}
-static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor6_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(left, top[-1]);
return pred;
}
-static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor7_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(left, top[0]);
return pred;
}
-static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor8_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(top[-1], top[0]);
(void)left;
return pred;
}
-static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor9_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average2(top[0], top[1]);
(void)left;
return pred;
}
-static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor10_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
return pred;
}
-static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor11_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = Select(top[0], left, top[-1]);
return pred;
}
-static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor12_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
return pred;
}
-static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
+static uint32_t Predictor13_C(uint32_t left, const uint32_t* const top) {
const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
return pred;
}
-GENERATE_PREDICTOR_ADD(Predictor0, PredictorAdd0)
-static void PredictorAdd1(const uint32_t* in, const uint32_t* upper,
- int num_pixels, uint32_t* out) {
+GENERATE_PREDICTOR_ADD(Predictor0_C, PredictorAdd0_C)
+static void PredictorAdd1_C(const uint32_t* in, const uint32_t* upper,
+ int num_pixels, uint32_t* out) {
int i;
uint32_t left = out[-1];
for (i = 0; i < num_pixels; ++i) {
@@ -177,29 +179,29 @@ static void PredictorAdd1(const uint32_t* in, const uint32_t* upper,
}
(void)upper;
}
-GENERATE_PREDICTOR_ADD(Predictor2, PredictorAdd2)
-GENERATE_PREDICTOR_ADD(Predictor3, PredictorAdd3)
-GENERATE_PREDICTOR_ADD(Predictor4, PredictorAdd4)
-GENERATE_PREDICTOR_ADD(Predictor5, PredictorAdd5)
-GENERATE_PREDICTOR_ADD(Predictor6, PredictorAdd6)
-GENERATE_PREDICTOR_ADD(Predictor7, PredictorAdd7)
-GENERATE_PREDICTOR_ADD(Predictor8, PredictorAdd8)
-GENERATE_PREDICTOR_ADD(Predictor9, PredictorAdd9)
-GENERATE_PREDICTOR_ADD(Predictor10, PredictorAdd10)
-GENERATE_PREDICTOR_ADD(Predictor11, PredictorAdd11)
-GENERATE_PREDICTOR_ADD(Predictor12, PredictorAdd12)
-GENERATE_PREDICTOR_ADD(Predictor13, PredictorAdd13)
+GENERATE_PREDICTOR_ADD(Predictor2_C, PredictorAdd2_C)
+GENERATE_PREDICTOR_ADD(Predictor3_C, PredictorAdd3_C)
+GENERATE_PREDICTOR_ADD(Predictor4_C, PredictorAdd4_C)
+GENERATE_PREDICTOR_ADD(Predictor5_C, PredictorAdd5_C)
+GENERATE_PREDICTOR_ADD(Predictor6_C, PredictorAdd6_C)
+GENERATE_PREDICTOR_ADD(Predictor7_C, PredictorAdd7_C)
+GENERATE_PREDICTOR_ADD(Predictor8_C, PredictorAdd8_C)
+GENERATE_PREDICTOR_ADD(Predictor9_C, PredictorAdd9_C)
+GENERATE_PREDICTOR_ADD(Predictor10_C, PredictorAdd10_C)
+GENERATE_PREDICTOR_ADD(Predictor11_C, PredictorAdd11_C)
+GENERATE_PREDICTOR_ADD(Predictor12_C, PredictorAdd12_C)
+GENERATE_PREDICTOR_ADD(Predictor13_C, PredictorAdd13_C)
//------------------------------------------------------------------------------
// Inverse prediction.
-static void PredictorInverseTransform(const VP8LTransform* const transform,
- int y_start, int y_end,
- const uint32_t* in, uint32_t* out) {
+static void PredictorInverseTransform_C(const VP8LTransform* const transform,
+ int y_start, int y_end,
+ const uint32_t* in, uint32_t* out) {
const int width = transform->xsize_;
if (y_start == 0) { // First Row follows the L (mode=1) mode.
- PredictorAdd0(in, NULL, 1, out);
- PredictorAdd1(in + 1, NULL, width - 1, out + 1);
+ PredictorAdd0_C(in, NULL, 1, out);
+ PredictorAdd1_C(in + 1, NULL, width - 1, out + 1);
in += width;
out += width;
++y_start;
@@ -217,7 +219,7 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
const uint32_t* pred_mode_src = pred_mode_base;
int x = 1;
// First pixel follows the T (mode=2) mode.
- PredictorAdd2(in, out - width, 1, out);
+ PredictorAdd2_C(in, out - width, 1, out);
// .. the rest:
while (x < width) {
const VP8LPredictorAddSubFunc pred_func =
@@ -272,8 +274,8 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
const uint32_t argb = src[i];
const uint32_t green = argb >> 8;
const uint32_t red = argb >> 16;
- int new_red = red;
- int new_blue = argb;
+ int new_red = red & 0xff;
+ int new_blue = argb & 0xff;
new_red += ColorTransformDelta(m->green_to_red_, green);
new_red &= 0xff;
new_blue += ColorTransformDelta(m->green_to_blue_, green);
@@ -284,9 +286,9 @@ void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
}
// Color space inverse transform.
-static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
- int y_start, int y_end,
- const uint32_t* src, uint32_t* dst) {
+static void ColorSpaceInverseTransform_C(const VP8LTransform* const transform,
+ int y_start, int y_end,
+ const uint32_t* src, uint32_t* dst) {
const int width = transform->xsize_;
const int tile_width = 1 << transform->bits_;
const int mask = tile_width - 1;
@@ -362,10 +364,10 @@ STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \
} \
}
-COLOR_INDEX_INVERSE(ColorIndexInverseTransform, MapARGB, static, uint32_t, 32b,
- VP8GetARGBIndex, VP8GetARGBValue)
-COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha, , uint8_t,
- 8b, VP8GetAlphaIndex, VP8GetAlphaValue)
+COLOR_INDEX_INVERSE(ColorIndexInverseTransform_C, MapARGB_C, static,
+ uint32_t, 32b, VP8GetARGBIndex, VP8GetARGBValue)
+COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha_C, ,
+ uint8_t, 8b, VP8GetAlphaIndex, VP8GetAlphaValue)
#undef COLOR_INDEX_INVERSE
@@ -380,7 +382,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out);
break;
case PREDICTOR_TRANSFORM:
- PredictorInverseTransform(transform, row_start, row_end, in, out);
+ PredictorInverseTransform_C(transform, row_start, row_end, in, out);
if (row_end != transform->ysize_) {
// The last predicted row in this iteration will be the top-pred row
// for the first row in next iteration.
@@ -389,7 +391,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
}
break;
case CROSS_COLOR_TRANSFORM:
- ColorSpaceInverseTransform(transform, row_start, row_end, in, out);
+ ColorSpaceInverseTransform_C(transform, row_start, row_end, in, out);
break;
case COLOR_INDEXING_TRANSFORM:
if (in == out && transform->bits_ > 0) {
@@ -403,9 +405,9 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
VP8LSubSampleSize(transform->xsize_, transform->bits_);
uint32_t* const src = out + out_stride - in_stride;
memmove(src, out, in_stride * sizeof(*src));
- ColorIndexInverseTransform(transform, row_start, row_end, src, out);
+ ColorIndexInverseTransform_C(transform, row_start, row_end, src, out);
} else {
- ColorIndexInverseTransform(transform, row_start, row_end, in, out);
+ ColorIndexInverseTransform_C(transform, row_start, row_end, in, out);
}
break;
}
@@ -452,7 +454,7 @@ void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
const uint32_t argb = *src++;
const uint8_t rg = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
const uint8_t ba = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
*dst++ = ba;
*dst++ = rg;
#else
@@ -469,7 +471,7 @@ void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
const uint32_t argb = *src++;
const uint8_t rg = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
const uint8_t gb = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
*dst++ = gb;
*dst++ = rg;
#else
@@ -496,22 +498,7 @@ static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
-
-#if !defined(WORDS_BIGENDIAN)
-#if !defined(WEBP_REFERENCE_IMPLEMENTATION)
WebPUint32ToMem(dst, BSwap32(argb));
-#else // WEBP_REFERENCE_IMPLEMENTATION
- dst[0] = (argb >> 24) & 0xff;
- dst[1] = (argb >> 16) & 0xff;
- dst[2] = (argb >> 8) & 0xff;
- dst[3] = (argb >> 0) & 0xff;
-#endif
-#else // WORDS_BIGENDIAN
- dst[0] = (argb >> 0) & 0xff;
- dst[1] = (argb >> 8) & 0xff;
- dst[2] = (argb >> 16) & 0xff;
- dst[3] = (argb >> 24) & 0xff;
-#endif
dst += sizeof(argb);
}
} else {
@@ -590,48 +577,46 @@ extern void VP8LDspInitNEON(void);
extern void VP8LDspInitMIPSdspR2(void);
extern void VP8LDspInitMSA(void);
-static volatile VP8CPUInfo lossless_last_cpuinfo_used =
- (VP8CPUInfo)&lossless_last_cpuinfo_used;
-
-#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \
- (OUT)[0] = IN##0; \
- (OUT)[1] = IN##1; \
- (OUT)[2] = IN##2; \
- (OUT)[3] = IN##3; \
- (OUT)[4] = IN##4; \
- (OUT)[5] = IN##5; \
- (OUT)[6] = IN##6; \
- (OUT)[7] = IN##7; \
- (OUT)[8] = IN##8; \
- (OUT)[9] = IN##9; \
- (OUT)[10] = IN##10; \
- (OUT)[11] = IN##11; \
- (OUT)[12] = IN##12; \
- (OUT)[13] = IN##13; \
- (OUT)[14] = IN##0; /* <- padding security sentinels*/ \
- (OUT)[15] = IN##0; \
+#define COPY_PREDICTOR_ARRAY(IN, OUT) do { \
+ (OUT)[0] = IN##0_C; \
+ (OUT)[1] = IN##1_C; \
+ (OUT)[2] = IN##2_C; \
+ (OUT)[3] = IN##3_C; \
+ (OUT)[4] = IN##4_C; \
+ (OUT)[5] = IN##5_C; \
+ (OUT)[6] = IN##6_C; \
+ (OUT)[7] = IN##7_C; \
+ (OUT)[8] = IN##8_C; \
+ (OUT)[9] = IN##9_C; \
+ (OUT)[10] = IN##10_C; \
+ (OUT)[11] = IN##11_C; \
+ (OUT)[12] = IN##12_C; \
+ (OUT)[13] = IN##13_C; \
+ (OUT)[14] = IN##0_C; /* <- padding security sentinels*/ \
+ (OUT)[15] = IN##0_C; \
} while (0);
-WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
- if (lossless_last_cpuinfo_used == VP8GetCPUInfo) return;
-
+WEBP_DSP_INIT_FUNC(VP8LDspInit) {
COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors)
COPY_PREDICTOR_ARRAY(Predictor, VP8LPredictors_C)
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd)
COPY_PREDICTOR_ARRAY(PredictorAdd, VP8LPredictorsAdd_C)
+#if !WEBP_NEON_OMIT_C_CODE
VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
VP8LTransformColorInverse = VP8LTransformColorInverse_C;
- VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;
+ VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
+ VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
+#endif
+
VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;
VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;
- VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
- VP8LMapColor32b = MapARGB;
- VP8LMapColor8b = MapAlpha;
+ VP8LMapColor32b = MapARGB_C;
+ VP8LMapColor8b = MapAlpha_C;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
@@ -640,11 +625,6 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
VP8LDspInitSSE2();
}
#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- VP8LDspInitNEON();
- }
-#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
if (VP8GetCPUInfo(kMIPSdspR2)) {
VP8LDspInitMIPSdspR2();
@@ -656,7 +636,23 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
}
#endif
}
- lossless_last_cpuinfo_used = VP8GetCPUInfo;
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ VP8LDspInitNEON();
+ }
+#endif
+
+ assert(VP8LAddGreenToBlueAndRed != NULL);
+ assert(VP8LTransformColorInverse != NULL);
+ assert(VP8LConvertBGRAToRGBA != NULL);
+ assert(VP8LConvertBGRAToRGB != NULL);
+ assert(VP8LConvertBGRAToBGR != NULL);
+ assert(VP8LConvertBGRAToRGBA4444 != NULL);
+ assert(VP8LConvertBGRAToRGB565 != NULL);
+ assert(VP8LMapColor32b != NULL);
+ assert(VP8LMapColor8b != NULL);
}
#undef COPY_PREDICTOR_ARRAY
diff --git a/media/libwebp/dsp/lossless.h b/media/libwebp/dsp/lossless.h
index 352a54e50..4a1d1e0dd 100644
--- a/media/libwebp/dsp/lossless.h
+++ b/media/libwebp/dsp/lossless.h
@@ -25,10 +25,6 @@
extern "C" {
#endif
-#ifdef WEBP_EXPERIMENTAL_FEATURES
-#include "../enc/delta_palettization_enc.h"
-#endif // WEBP_EXPERIMENTAL_FEATURES
-
//------------------------------------------------------------------------------
// Decoding
@@ -124,7 +120,7 @@ void VP8LDspInit(void);
typedef void (*VP8LProcessEncBlueAndRedFunc)(uint32_t* dst, int num_pixels);
extern VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m,
- uint32_t* const dst, int num_pixels);
+ uint32_t* dst, int num_pixels);
extern VP8LTransformColorFunc VP8LTransformColor;
typedef void (*VP8LCollectColorBlueTransformsFunc)(
const uint32_t* argb, int stride,
diff --git a/media/libwebp/dsp/lossless_common.h b/media/libwebp/dsp/lossless_common.h
index c40f71120..dd2e4f247 100644
--- a/media/libwebp/dsp/lossless_common.h
+++ b/media/libwebp/dsp/lossless_common.h
@@ -93,14 +93,6 @@ static WEBP_INLINE float VP8LFastSLog2(uint32_t v) {
// -----------------------------------------------------------------------------
// PrefixEncode()
-static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) {
- const int log_floor = BitsLog2Floor(n);
- if (n == (n & ~(n - 1))) { // zero or a power of two.
- return log_floor;
- }
- return log_floor + 1;
-}
-
// Splitting of distance and length codes into prefixes and
// extra bits. The prefixes are encoded with an entropy code
// while the extra bits are stored just as normal bits.
diff --git a/media/libwebp/dsp/lossless_neon.c b/media/libwebp/dsp/lossless_neon.c
index 1145d5fad..a7bf47f3c 100644
--- a/media/libwebp/dsp/lossless_neon.c
+++ b/media/libwebp/dsp/lossless_neon.c
@@ -11,14 +11,14 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_NEON)
#include <arm_neon.h>
-#include "./lossless.h"
-#include "./neon.h"
+#include "../dsp/lossless.h"
+#include "../dsp/neon.h"
//------------------------------------------------------------------------------
// Colorspace conversion functions
@@ -26,8 +26,8 @@
#if !defined(WORK_AROUND_GCC)
// gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for
// gcc-4.8.x at least.
-static void ConvertBGRAToRGBA(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGBA_NEON(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const end = src + (num_pixels & ~15);
for (; src < end; src += 16) {
uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
@@ -41,8 +41,8 @@ static void ConvertBGRAToRGBA(const uint32_t* src,
VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs
}
-static void ConvertBGRAToBGR(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToBGR_NEON(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const end = src + (num_pixels & ~15);
for (; src < end; src += 16) {
const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
@@ -53,8 +53,8 @@ static void ConvertBGRAToBGR(const uint32_t* src,
VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs
}
-static void ConvertBGRAToRGB(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGB_NEON(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const end = src + (num_pixels & ~15);
for (; src < end; src += 16) {
const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
@@ -71,8 +71,8 @@ static void ConvertBGRAToRGB(const uint32_t* src,
static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 };
-static void ConvertBGRAToRGBA(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGBA_NEON(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const end = src + (num_pixels & ~1);
const uint8x8_t shuffle = vld1_u8(kRGBAShuffle);
for (; src < end; src += 2) {
@@ -89,8 +89,8 @@ static const uint8_t kBGRShuffle[3][8] = {
{ 21, 22, 24, 25, 26, 28, 29, 30 }
};
-static void ConvertBGRAToBGR(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToBGR_NEON(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const end = src + (num_pixels & ~7);
const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]);
const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]);
@@ -116,8 +116,8 @@ static const uint8_t kRGBShuffle[3][8] = {
{ 21, 20, 26, 25, 24, 30, 29, 28 }
};
-static void ConvertBGRAToRGB(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGB_NEON(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const end = src + (num_pixels & ~7);
const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]);
const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]);
@@ -139,7 +139,6 @@ static void ConvertBGRAToRGB(const uint32_t* src,
#endif // !WORK_AROUND_GCC
-
//------------------------------------------------------------------------------
// Predictor Transform
@@ -506,8 +505,8 @@ static const uint8_t kGreenShuffle[16] = {
1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255
};
-static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
- const uint8x16_t shuffle) {
+static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb,
+ const uint8x16_t shuffle) {
return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)),
vtbl1q_u8(argb, vget_high_u8(shuffle)));
}
@@ -515,15 +514,15 @@ static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
// 255 = byte will be zeroed
static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 };
-static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
- const uint8x8_t shuffle) {
+static WEBP_INLINE uint8x16_t DoGreenShuffle_NEON(const uint8x16_t argb,
+ const uint8x8_t shuffle) {
return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle),
vtbl1_u8(vget_high_u8(argb), shuffle));
}
#endif // USE_VTBLQ
-static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels,
- uint32_t* dst) {
+static void AddGreenToBlueAndRed_NEON(const uint32_t* src, int num_pixels,
+ uint32_t* dst) {
const uint32_t* const end = src + (num_pixels & ~3);
#ifdef USE_VTBLQ
const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
@@ -532,7 +531,7 @@ static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels,
#endif
for (; src < end; src += 4, dst += 4) {
const uint8x16_t argb = vld1q_u8((const uint8_t*)src);
- const uint8x16_t greens = DoGreenShuffle(argb, shuffle);
+ const uint8x16_t greens = DoGreenShuffle_NEON(argb, shuffle);
vst1q_u8((uint8_t*)dst, vaddq_u8(argb, greens));
}
// fallthrough and finish off with plain-C
@@ -542,9 +541,9 @@ static void AddGreenToBlueAndRed(const uint32_t* src, int num_pixels,
//------------------------------------------------------------------------------
// Color Transform
-static void TransformColorInverse(const VP8LMultipliers* const m,
- const uint32_t* const src, int num_pixels,
- uint32_t* dst) {
+static void TransformColorInverse_NEON(const VP8LMultipliers* const m,
+ const uint32_t* const src,
+ int num_pixels, uint32_t* dst) {
// sign-extended multiplying constants, pre-shifted by 6.
#define CST(X) (((int16_t)(m->X << 8)) >> 6)
const int16_t rb[8] = {
@@ -575,7 +574,7 @@ static void TransformColorInverse(const VP8LMultipliers* const m,
const uint8x16_t in = vld1q_u8((const uint8_t*)(src + i));
const uint32x4_t a0g0 = vandq_u32(vreinterpretq_u32_u8(in), mask_ag);
// 0 g 0 g
- const uint8x16_t greens = DoGreenShuffle(in, shuffle);
+ const uint8x16_t greens = DoGreenShuffle_NEON(in, shuffle);
// x dr x db1
const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb);
// x r' x b'
@@ -627,12 +626,12 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitNEON(void) {
VP8LPredictorsAdd[12] = PredictorAdd12_NEON;
VP8LPredictorsAdd[13] = PredictorAdd13_NEON;
- VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
- VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
- VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_NEON;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR_NEON;
+ VP8LConvertBGRAToRGB = ConvertBGRAToRGB_NEON;
- VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
- VP8LTransformColorInverse = TransformColorInverse;
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_NEON;
+ VP8LTransformColorInverse = TransformColorInverse_NEON;
}
#else // !WEBP_USE_NEON
diff --git a/media/libwebp/dsp/lossless_sse2.c b/media/libwebp/dsp/lossless_sse2.c
index 15aae9386..c40fcfb76 100644
--- a/media/libwebp/dsp/lossless_sse2.c
+++ b/media/libwebp/dsp/lossless_sse2.c
@@ -11,21 +11,22 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE2)
-#include "./common_sse2.h"
-#include "./lossless.h"
-#include "./lossless_common.h"
+#include "../dsp/common_sse2.h"
+#include "../dsp/lossless.h"
+#include "../dsp/lossless_common.h"
#include <assert.h>
#include <emmintrin.h>
//------------------------------------------------------------------------------
// Predictor Transform
-static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
- uint32_t c2) {
+static WEBP_INLINE uint32_t ClampedAddSubtractFull_SSE2(uint32_t c0,
+ uint32_t c1,
+ uint32_t c2) {
const __m128i zero = _mm_setzero_si128();
const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
@@ -37,8 +38,9 @@ static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
return output;
}
-static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
- uint32_t c2) {
+static WEBP_INLINE uint32_t ClampedAddSubtractHalf_SSE2(uint32_t c0,
+ uint32_t c1,
+ uint32_t c2) {
const __m128i zero = _mm_setzero_si128();
const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
@@ -55,7 +57,7 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
return output;
}
-static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
+static WEBP_INLINE uint32_t Select_SSE2(uint32_t a, uint32_t b, uint32_t c) {
int pa_minus_pb;
const __m128i zero = _mm_setzero_si128();
const __m128i A0 = _mm_cvtsi32_si128(a);
@@ -88,8 +90,9 @@ static WEBP_INLINE void Average2_m128i(const __m128i* const a0,
*avg = _mm_sub_epi8(avg1, one);
}
-static WEBP_INLINE void Average2_uint32(const uint32_t a0, const uint32_t a1,
- __m128i* const avg) {
+static WEBP_INLINE void Average2_uint32_SSE2(const uint32_t a0,
+ const uint32_t a1,
+ __m128i* const avg) {
// (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
const __m128i ones = _mm_set1_epi8(1);
const __m128i A0 = _mm_cvtsi32_si128(a0);
@@ -99,7 +102,7 @@ static WEBP_INLINE void Average2_uint32(const uint32_t a0, const uint32_t a1,
*avg = _mm_sub_epi8(avg1, one);
}
-static WEBP_INLINE __m128i Average2_uint32_16(uint32_t a0, uint32_t a1) {
+static WEBP_INLINE __m128i Average2_uint32_16_SSE2(uint32_t a0, uint32_t a1) {
const __m128i zero = _mm_setzero_si128();
const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
@@ -107,15 +110,16 @@ static WEBP_INLINE __m128i Average2_uint32_16(uint32_t a0, uint32_t a1) {
return _mm_srli_epi16(sum, 1);
}
-static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
+static WEBP_INLINE uint32_t Average2_SSE2(uint32_t a0, uint32_t a1) {
__m128i output;
- Average2_uint32(a0, a1, &output);
+ Average2_uint32_SSE2(a0, a1, &output);
return _mm_cvtsi128_si32(output);
}
-static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
+static WEBP_INLINE uint32_t Average3_SSE2(uint32_t a0, uint32_t a1,
+ uint32_t a2) {
const __m128i zero = _mm_setzero_si128();
- const __m128i avg1 = Average2_uint32_16(a0, a2);
+ const __m128i avg1 = Average2_uint32_16_SSE2(a0, a2);
const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
const __m128i sum = _mm_add_epi16(avg1, A1);
const __m128i avg2 = _mm_srli_epi16(sum, 1);
@@ -124,10 +128,10 @@ static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
return output;
}
-static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
- uint32_t a2, uint32_t a3) {
- const __m128i avg1 = Average2_uint32_16(a0, a1);
- const __m128i avg2 = Average2_uint32_16(a2, a3);
+static WEBP_INLINE uint32_t Average4_SSE2(uint32_t a0, uint32_t a1,
+ uint32_t a2, uint32_t a3) {
+ const __m128i avg1 = Average2_uint32_16_SSE2(a0, a1);
+ const __m128i avg2 = Average2_uint32_16_SSE2(a2, a3);
const __m128i sum = _mm_add_epi16(avg2, avg1);
const __m128i avg3 = _mm_srli_epi16(sum, 1);
const __m128i A0 = _mm_packus_epi16(avg3, avg3);
@@ -136,41 +140,41 @@ static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
}
static uint32_t Predictor5_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average3(left, top[0], top[1]);
+ const uint32_t pred = Average3_SSE2(left, top[0], top[1]);
return pred;
}
static uint32_t Predictor6_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(left, top[-1]);
+ const uint32_t pred = Average2_SSE2(left, top[-1]);
return pred;
}
static uint32_t Predictor7_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(left, top[0]);
+ const uint32_t pred = Average2_SSE2(left, top[0]);
return pred;
}
static uint32_t Predictor8_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(top[-1], top[0]);
+ const uint32_t pred = Average2_SSE2(top[-1], top[0]);
(void)left;
return pred;
}
static uint32_t Predictor9_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average2(top[0], top[1]);
+ const uint32_t pred = Average2_SSE2(top[0], top[1]);
(void)left;
return pred;
}
static uint32_t Predictor10_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
+ const uint32_t pred = Average4_SSE2(left, top[-1], top[0], top[1]);
return pred;
}
static uint32_t Predictor11_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = Select(top[0], left, top[-1]);
+ const uint32_t pred = Select_SSE2(top[0], left, top[-1]);
return pred;
}
static uint32_t Predictor12_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
+ const uint32_t pred = ClampedAddSubtractFull_SSE2(left, top[0], top[-1]);
return pred;
}
static uint32_t Predictor13_SSE2(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
+ const uint32_t pred = ClampedAddSubtractHalf_SSE2(left, top[0], top[-1]);
return pred;
}
@@ -272,9 +276,24 @@ GENERATE_PREDICTOR_2(9, upper[i + 1])
#undef GENERATE_PREDICTOR_2
// Predictor10: average of (average of (L,TL), average of (T, TR)).
+#define DO_PRED10(OUT) do { \
+ __m128i avgLTL, avg; \
+ Average2_m128i(&L, &TL, &avgLTL); \
+ Average2_m128i(&avgTTR, &avgLTL, &avg); \
+ L = _mm_add_epi8(avg, src); \
+ out[i + (OUT)] = _mm_cvtsi128_si32(L); \
+} while (0)
+
+#define DO_PRED10_SHIFT do { \
+ /* Rotate the pre-computed values for the next iteration.*/ \
+ avgTTR = _mm_srli_si128(avgTTR, 4); \
+ TL = _mm_srli_si128(TL, 4); \
+ src = _mm_srli_si128(src, 4); \
+} while (0)
+
static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
- int i, j;
+ int i;
__m128i L = _mm_cvtsi32_si128(out[-1]);
for (i = 0; i + 4 <= num_pixels; i += 4) {
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
@@ -283,79 +302,90 @@ static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]);
__m128i avgTTR;
Average2_m128i(&T, &TR, &avgTTR);
- for (j = 0; j < 4; ++j) {
- __m128i avgLTL, avg;
- Average2_m128i(&L, &TL, &avgLTL);
- Average2_m128i(&avgTTR, &avgLTL, &avg);
- L = _mm_add_epi8(avg, src);
- out[i + j] = _mm_cvtsi128_si32(L);
- // Rotate the pre-computed values for the next iteration.
- avgTTR = _mm_srli_si128(avgTTR, 4);
- TL = _mm_srli_si128(TL, 4);
- src = _mm_srli_si128(src, 4);
- }
+ DO_PRED10(0);
+ DO_PRED10_SHIFT;
+ DO_PRED10(1);
+ DO_PRED10_SHIFT;
+ DO_PRED10(2);
+ DO_PRED10_SHIFT;
+ DO_PRED10(3);
}
if (i != num_pixels) {
VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i);
}
}
+#undef DO_PRED10
+#undef DO_PRED10_SHIFT
// Predictor11: select.
-static void GetSumAbsDiff32(const __m128i* const A, const __m128i* const B,
- __m128i* const out) {
- // We can unpack with any value on the upper 32 bits, provided it's the same
- // on both operands (to that their sum of abs diff is zero). Here we use *A.
- const __m128i A_lo = _mm_unpacklo_epi32(*A, *A);
- const __m128i B_lo = _mm_unpacklo_epi32(*B, *A);
- const __m128i A_hi = _mm_unpackhi_epi32(*A, *A);
- const __m128i B_hi = _mm_unpackhi_epi32(*B, *A);
- const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo);
- const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi);
- *out = _mm_packs_epi32(s_lo, s_hi);
-}
+#define DO_PRED11(OUT) do { \
+ const __m128i L_lo = _mm_unpacklo_epi32(L, T); \
+ const __m128i TL_lo = _mm_unpacklo_epi32(TL, T); \
+ const __m128i pb = _mm_sad_epu8(L_lo, TL_lo); /* pb = sum |L-TL|*/ \
+ const __m128i mask = _mm_cmpgt_epi32(pb, pa); \
+ const __m128i A = _mm_and_si128(mask, L); \
+ const __m128i B = _mm_andnot_si128(mask, T); \
+ const __m128i pred = _mm_or_si128(A, B); /* pred = (pa > b)? L : T*/ \
+ L = _mm_add_epi8(src, pred); \
+ out[i + (OUT)] = _mm_cvtsi128_si32(L); \
+} while (0)
+
+#define DO_PRED11_SHIFT do { \
+ /* Shift the pre-computed value for the next iteration.*/ \
+ T = _mm_srli_si128(T, 4); \
+ TL = _mm_srli_si128(TL, 4); \
+ src = _mm_srli_si128(src, 4); \
+ pa = _mm_srli_si128(pa, 4); \
+} while (0)
static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper,
int num_pixels, uint32_t* out) {
- int i, j;
+ int i;
+ __m128i pa;
__m128i L = _mm_cvtsi32_si128(out[-1]);
for (i = 0; i + 4 <= num_pixels; i += 4) {
__m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
__m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
__m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
- __m128i pa;
- GetSumAbsDiff32(&T, &TL, &pa); // pa = sum |T-TL|
- for (j = 0; j < 4; ++j) {
- const __m128i L_lo = _mm_unpacklo_epi32(L, L);
- const __m128i TL_lo = _mm_unpacklo_epi32(TL, L);
- const __m128i pb = _mm_sad_epu8(L_lo, TL_lo); // pb = sum |L-TL|
- const __m128i mask = _mm_cmpgt_epi32(pb, pa);
- const __m128i A = _mm_and_si128(mask, L);
- const __m128i B = _mm_andnot_si128(mask, T);
- const __m128i pred = _mm_or_si128(A, B); // pred = (L > T)? L : T
- L = _mm_add_epi8(src, pred);
- out[i + j] = _mm_cvtsi128_si32(L);
- // Shift the pre-computed value for the next iteration.
- T = _mm_srli_si128(T, 4);
- TL = _mm_srli_si128(TL, 4);
- src = _mm_srli_si128(src, 4);
- pa = _mm_srli_si128(pa, 4);
+ {
+ // We can unpack with any value on the upper 32 bits, provided it's the
+ // same on both operands (so that their sum of abs diff is zero). Here we
+ // use T.
+ const __m128i T_lo = _mm_unpacklo_epi32(T, T);
+ const __m128i TL_lo = _mm_unpacklo_epi32(TL, T);
+ const __m128i T_hi = _mm_unpackhi_epi32(T, T);
+ const __m128i TL_hi = _mm_unpackhi_epi32(TL, T);
+ const __m128i s_lo = _mm_sad_epu8(T_lo, TL_lo);
+ const __m128i s_hi = _mm_sad_epu8(T_hi, TL_hi);
+ pa = _mm_packs_epi32(s_lo, s_hi); // pa = sum |T-TL|
}
+ DO_PRED11(0);
+ DO_PRED11_SHIFT;
+ DO_PRED11(1);
+ DO_PRED11_SHIFT;
+ DO_PRED11(2);
+ DO_PRED11_SHIFT;
+ DO_PRED11(3);
}
if (i != num_pixels) {
VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i);
}
}
+#undef DO_PRED11
+#undef DO_PRED11_SHIFT
// Predictor12: ClampedAddSubtractFull.
-#define DO_PRED12(DIFF, LANE, OUT) \
-do { \
- const __m128i all = _mm_add_epi16(L, (DIFF)); \
- const __m128i alls = _mm_packus_epi16(all, all); \
- const __m128i res = _mm_add_epi8(src, alls); \
- out[i + (OUT)] = _mm_cvtsi128_si32(res); \
- L = _mm_unpacklo_epi8(res, zero); \
+#define DO_PRED12(DIFF, LANE, OUT) do { \
+ const __m128i all = _mm_add_epi16(L, (DIFF)); \
+ const __m128i alls = _mm_packus_epi16(all, all); \
+ const __m128i res = _mm_add_epi8(src, alls); \
+ out[i + (OUT)] = _mm_cvtsi128_si32(res); \
+ L = _mm_unpacklo_epi8(res, zero); \
+} while (0)
+
+#define DO_PRED12_SHIFT(DIFF, LANE) do { \
/* Shift the pre-computed value for the next iteration.*/ \
- if (LANE == 0) (DIFF) = _mm_srli_si128((DIFF), 8); \
+ if ((LANE) == 0) (DIFF) = _mm_srli_si128((DIFF), 8); \
src = _mm_srli_si128(src, 4); \
} while (0)
@@ -377,8 +407,11 @@ static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper,
__m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo);
__m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi);
DO_PRED12(diff_lo, 0, 0);
+ DO_PRED12_SHIFT(diff_lo, 0);
DO_PRED12(diff_lo, 1, 1);
+ DO_PRED12_SHIFT(diff_lo, 1);
DO_PRED12(diff_hi, 0, 2);
+ DO_PRED12_SHIFT(diff_hi, 0);
DO_PRED12(diff_hi, 1, 3);
}
if (i != num_pixels) {
@@ -386,6 +419,7 @@ static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper,
}
}
#undef DO_PRED12
+#undef DO_PRED12_SHIFT
// Due to averages with integers, values cannot be accumulated in parallel for
// predictors 13.
@@ -394,8 +428,8 @@ GENERATE_PREDICTOR_ADD(Predictor13_SSE2, PredictorAdd13_SSE2)
//------------------------------------------------------------------------------
// Subtract-Green Transform
-static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels,
- uint32_t* dst) {
+static void AddGreenToBlueAndRed_SSE2(const uint32_t* const src, int num_pixels,
+ uint32_t* dst) {
int i;
for (i = 0; i + 4 <= num_pixels; i += 4) {
const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb
@@ -414,19 +448,16 @@ static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels,
//------------------------------------------------------------------------------
// Color Transform
-static void TransformColorInverse(const VP8LMultipliers* const m,
- const uint32_t* const src, int num_pixels,
- uint32_t* dst) {
+static void TransformColorInverse_SSE2(const VP8LMultipliers* const m,
+ const uint32_t* const src,
+ int num_pixels, uint32_t* dst) {
// sign-extended multiplying constants, pre-shifted by 5.
#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
- const __m128i mults_rb = _mm_set_epi16(
- CST(green_to_red_), CST(green_to_blue_),
- CST(green_to_red_), CST(green_to_blue_),
- CST(green_to_red_), CST(green_to_blue_),
- CST(green_to_red_), CST(green_to_blue_));
- const __m128i mults_b2 = _mm_set_epi16(
- CST(red_to_blue_), 0, CST(red_to_blue_), 0,
- CST(red_to_blue_), 0, CST(red_to_blue_), 0);
+#define MK_CST_16(HI, LO) \
+ _mm_set1_epi32((int)(((uint32_t)(HI) << 16) | ((LO) & 0xffff)))
+ const __m128i mults_rb = MK_CST_16(CST(green_to_red_), CST(green_to_blue_));
+ const __m128i mults_b2 = MK_CST_16(CST(red_to_blue_), 0);
+#undef MK_CST_16
#undef CST
const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
int i;
@@ -454,8 +485,8 @@ static void TransformColorInverse(const VP8LMultipliers* const m,
//------------------------------------------------------------------------------
// Color-space conversion functions
-static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
- uint8_t* dst) {
+static void ConvertBGRAToRGB_SSE2(const uint32_t* src, int num_pixels,
+ uint8_t* dst) {
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
@@ -469,11 +500,11 @@ static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
__m128i in5 = _mm_loadu_si128(in + 5);
__m128i in6 = _mm_loadu_si128(in + 6);
__m128i in7 = _mm_loadu_si128(in + 7);
- VP8L32bToPlanar(&in0, &in1, &in2, &in3);
- VP8L32bToPlanar(&in4, &in5, &in6, &in7);
+ VP8L32bToPlanar_SSE2(&in0, &in1, &in2, &in3);
+ VP8L32bToPlanar_SSE2(&in4, &in5, &in6, &in7);
// At this points, in1/in5 contains red only, in2/in6 green only ...
// Pack the colors in 24b RGB.
- VP8PlanarTo24b(&in1, &in5, &in2, &in6, &in3, &in7);
+ VP8PlanarTo24b_SSE2(&in1, &in5, &in2, &in6, &in3, &in7);
_mm_storeu_si128(out + 0, in1);
_mm_storeu_si128(out + 1, in5);
_mm_storeu_si128(out + 2, in2);
@@ -490,27 +521,26 @@ static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
}
}
-static void ConvertBGRAToRGBA(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGBA_SSE2(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ffu);
const __m128i* in = (const __m128i*)src;
__m128i* out = (__m128i*)dst;
while (num_pixels >= 8) {
- const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
- const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
- const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
- const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
- const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
- const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
- const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
- const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
- const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
- const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
- const __m128i rg0 = _mm_unpacklo_epi8(rb0, ga0); // r0g0r1g1 ... r6g6r7g7
- const __m128i ba0 = _mm_unpackhi_epi8(rb0, ga0); // b0a0b1a1 ... b6a6b7a7
- const __m128i rgba0 = _mm_unpacklo_epi16(rg0, ba0); // rgba0|rgba1...
- const __m128i rgba4 = _mm_unpackhi_epi16(rg0, ba0); // rgba4|rgba5...
- _mm_storeu_si128(out++, rgba0);
- _mm_storeu_si128(out++, rgba4);
+ const __m128i A1 = _mm_loadu_si128(in++);
+ const __m128i A2 = _mm_loadu_si128(in++);
+ const __m128i B1 = _mm_and_si128(A1, red_blue_mask); // R 0 B 0
+ const __m128i B2 = _mm_and_si128(A2, red_blue_mask); // R 0 B 0
+ const __m128i C1 = _mm_andnot_si128(red_blue_mask, A1); // 0 G 0 A
+ const __m128i C2 = _mm_andnot_si128(red_blue_mask, A2); // 0 G 0 A
+ const __m128i D1 = _mm_shufflelo_epi16(B1, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i D2 = _mm_shufflelo_epi16(B2, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i E1 = _mm_shufflehi_epi16(D1, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i E2 = _mm_shufflehi_epi16(D2, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i F1 = _mm_or_si128(E1, C1);
+ const __m128i F2 = _mm_or_si128(E2, C2);
+ _mm_storeu_si128(out++, F1);
+ _mm_storeu_si128(out++, F2);
num_pixels -= 8;
}
// left-overs
@@ -519,8 +549,8 @@ static void ConvertBGRAToRGBA(const uint32_t* src,
}
}
-static void ConvertBGRAToRGBA4444(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGBA4444_SSE2(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
const __m128i* in = (const __m128i*)src;
@@ -541,7 +571,7 @@ static void ConvertBGRAToRGBA4444(const uint32_t* src,
const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f); // g0-|g1-|...|a6-|a7-
const __m128i rgba0 = _mm_or_si128(ga2, rb1); // rg0..rg7 | ba0..ba7
const __m128i rgba1 = _mm_srli_si128(rgba0, 8); // ba0..ba7 | 0
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0); // barg0...barg7
#else
const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1); // rgba0...rgba7
@@ -555,8 +585,8 @@ static void ConvertBGRAToRGBA4444(const uint32_t* src,
}
}
-static void ConvertBGRAToRGB565(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToRGB565_SSE2(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
const __m128i mask_0x07 = _mm_set1_epi8(0x07);
@@ -582,7 +612,7 @@ static void ConvertBGRAToRGB565(const uint32_t* src,
const __m128i rg1 = _mm_or_si128(rb1, g_lo2); // gr0...gr7|xx
const __m128i b1 = _mm_srli_epi16(b0, 3);
const __m128i gb1 = _mm_or_si128(b1, g_hi2); // bg0...bg7|xx
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1); // rggb0...rggb7
#else
const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1); // bgrb0...bgrb7
@@ -596,8 +626,8 @@ static void ConvertBGRAToRGB565(const uint32_t* src,
}
}
-static void ConvertBGRAToBGR(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+static void ConvertBGRAToBGR_SSE2(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff);
const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0);
const __m128i* in = (const __m128i*)src;
@@ -660,14 +690,14 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) {
VP8LPredictorsAdd[12] = PredictorAdd12_SSE2;
VP8LPredictorsAdd[13] = PredictorAdd13_SSE2;
- VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
- VP8LTransformColorInverse = TransformColorInverse;
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_SSE2;
+ VP8LTransformColorInverse = TransformColorInverse_SSE2;
- VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
- VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
- VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
- VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
- VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
+ VP8LConvertBGRAToRGB = ConvertBGRAToRGB_SSE2;
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_SSE2;
+ VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_SSE2;
+ VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_SSE2;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR_SSE2;
}
#else // !WEBP_USE_SSE2
diff --git a/media/libwebp/dsp/moz.build b/media/libwebp/dsp/moz.build
index 006a691a0..fa6df9e9e 100644
--- a/media/libwebp/dsp/moz.build
+++ b/media/libwebp/dsp/moz.build
@@ -27,8 +27,10 @@ SOURCES += [
'upsampling.c',
'upsampling_neon.c',
'upsampling_sse2.c',
+ 'upsampling_sse41.c',
'yuv.c',
'yuv_sse2.c',
+ 'yuv_sse41.c',
]
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
@@ -45,7 +47,9 @@ elif CONFIG['INTEL_ARCHITECTURE']:
SOURCES['lossless_sse2.c'].flags += CONFIG['SSE2_FLAGS']
SOURCES['rescaler_sse2.c'].flags += CONFIG['SSE2_FLAGS']
SOURCES['upsampling_sse2.c'].flags += CONFIG['SSE2_FLAGS']
+ SOURCES['upsampling_sse41.c'].flags += CONFIG['SSE2_FLAGS']
SOURCES['yuv_sse2.c'].flags += CONFIG['SSE2_FLAGS']
+ SOURCES['yuv_sse41.c'].flags += CONFIG['SSE2_FLAGS']
FINAL_LIBRARY = 'gkmedias'
diff --git a/media/libwebp/dsp/msa_macro.h b/media/libwebp/dsp/msa_macro.h
index d0e5f45e0..dfacda6cc 100644
--- a/media/libwebp/dsp/msa_macro.h
+++ b/media/libwebp/dsp/msa_macro.h
@@ -22,6 +22,7 @@
#endif
#ifdef CLANG_BUILD
+ #define ALPHAVAL (-1)
#define ADDVI_H(a, b) __msa_addvi_h((v8i16)a, b)
#define ADDVI_W(a, b) __msa_addvi_w((v4i32)a, b)
#define SRAI_B(a, b) __msa_srai_b((v16i8)a, b)
@@ -32,6 +33,7 @@
#define ANDI_B(a, b) __msa_andi_b((v16u8)a, b)
#define ORI_B(a, b) __msa_ori_b((v16u8)a, b)
#else
+ #define ALPHAVAL (0xff)
#define ADDVI_H(a, b) (a + b)
#define ADDVI_W(a, b) (a + b)
#define SRAI_B(a, b) (a >> b)
diff --git a/media/libwebp/dsp/neon.h b/media/libwebp/dsp/neon.h
index 3b548a685..63c27a290 100644
--- a/media/libwebp/dsp/neon.h
+++ b/media/libwebp/dsp/neon.h
@@ -14,11 +14,12 @@
#include <arm_neon.h>
-#include "./dsp.h"
+#include "../dsp/dsp.h"
// Right now, some intrinsics functions seem slower, so we disable them
-// everywhere except aarch64 where the inline assembly is incompatible.
-#if defined(__aarch64__)
+// everywhere except newer clang/gcc or aarch64 where the inline assembly is
+// incompatible.
+#if LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,9) || defined(__aarch64__)
#define WEBP_USE_INTRINSICS // use intrinsics when possible
#endif
@@ -43,11 +44,11 @@
// if using intrinsics, this flag avoids some functions that make gcc-4.6.3
// crash ("internal compiler error: in immed_double_const, at emit-rtl.").
// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183)
-#if !(LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
+#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
#define WORK_AROUND_GCC
#endif
-static WEBP_INLINE int32x4x4_t Transpose4x4(const int32x4x4_t rows) {
+static WEBP_INLINE int32x4x4_t Transpose4x4_NEON(const int32x4x4_t rows) {
uint64x2x2_t row01, row23;
row01.val[0] = vreinterpretq_u64_s32(rows.val[0]);
diff --git a/media/libwebp/dsp/rescaler.c b/media/libwebp/dsp/rescaler.c
index 0f5450235..f70e6beef 100644
--- a/media/libwebp/dsp/rescaler.c
+++ b/media/libwebp/dsp/rescaler.c
@@ -13,7 +13,7 @@
#include <assert.h>
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#include "../utils/rescaler_utils.h"
//------------------------------------------------------------------------------
@@ -25,7 +25,8 @@
//------------------------------------------------------------------------------
// Row import
-void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
+void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
+ const uint8_t* src) {
const int x_stride = wrk->num_channels;
const int x_out_max = wrk->dst_width * wrk->num_channels;
int channel;
@@ -56,7 +57,8 @@ void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
}
}
-void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
+void WebPRescalerImportRowShrink_C(WebPRescaler* const wrk,
+ const uint8_t* src) {
const int x_stride = wrk->num_channels;
const int x_out_max = wrk->dst_width * wrk->num_channels;
int channel;
@@ -92,7 +94,7 @@ void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
//------------------------------------------------------------------------------
// Row export
-void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
+void WebPRescalerExportRowExpand_C(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
rescaler_t* const irow = wrk->irow;
@@ -123,7 +125,7 @@ void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
}
}
-void WebPRescalerExportRowShrinkC(WebPRescaler* const wrk) {
+void WebPRescalerExportRowShrink_C(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
rescaler_t* const irow = wrk->irow;
@@ -202,16 +204,15 @@ extern void WebPRescalerDspInitMIPSdspR2(void);
extern void WebPRescalerDspInitMSA(void);
extern void WebPRescalerDspInitNEON(void);
-static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
- (VP8CPUInfo)&rescaler_last_cpuinfo_used;
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
- if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
+WEBP_DSP_INIT_FUNC(WebPRescalerDspInit) {
+#if !defined(WEBP_REDUCE_SIZE)
+#if !WEBP_NEON_OMIT_C_CODE
+ WebPRescalerExportRowExpand = WebPRescalerExportRowExpand_C;
+ WebPRescalerExportRowShrink = WebPRescalerExportRowShrink_C;
+#endif
- WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC;
- WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC;
- WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC;
- WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC;
+ WebPRescalerImportRowExpand = WebPRescalerImportRowExpand_C;
+ WebPRescalerImportRowShrink = WebPRescalerImportRowShrink_C;
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
@@ -219,11 +220,6 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
WebPRescalerDspInitSSE2();
}
#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- WebPRescalerDspInitNEON();
- }
-#endif
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
WebPRescalerDspInitMIPS32();
@@ -240,5 +236,17 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
}
#endif
}
- rescaler_last_cpuinfo_used = VP8GetCPUInfo;
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ WebPRescalerDspInitNEON();
+ }
+#endif
+
+ assert(WebPRescalerExportRowExpand != NULL);
+ assert(WebPRescalerExportRowShrink != NULL);
+ assert(WebPRescalerImportRowExpand != NULL);
+ assert(WebPRescalerImportRowShrink != NULL);
+#endif // WEBP_REDUCE_SIZE
}
diff --git a/media/libwebp/dsp/rescaler_neon.c b/media/libwebp/dsp/rescaler_neon.c
index b2dd8f30c..835e646c1 100644
--- a/media/libwebp/dsp/rescaler_neon.c
+++ b/media/libwebp/dsp/rescaler_neon.c
@@ -11,13 +11,13 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
-#if defined(WEBP_USE_NEON)
+#if defined(WEBP_USE_NEON) && !defined(WEBP_REDUCE_SIZE)
#include <arm_neon.h>
#include <assert.h>
-#include "./neon.h"
+#include "../dsp/neon.h"
#include "../utils/rescaler_utils.h"
#define ROUNDER (WEBP_RESCALER_ONE >> 1)
@@ -41,9 +41,9 @@
#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
#endif
-static uint32x4_t Interpolate(const rescaler_t* const frow,
- const rescaler_t* const irow,
- uint32_t A, uint32_t B) {
+static uint32x4_t Interpolate_NEON(const rescaler_t* const frow,
+ const rescaler_t* const irow,
+ uint32_t A, uint32_t B) {
LOAD_32x4(frow, A0);
LOAD_32x4(irow, B0);
const uint64x2_t C0 = vmull_n_u32(vget_low_u32(A0), A);
@@ -56,7 +56,7 @@ static uint32x4_t Interpolate(const rescaler_t* const frow,
return E;
}
-static void RescalerExportRowExpand(WebPRescaler* const wrk) {
+static void RescalerExportRowExpand_NEON(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
rescaler_t* const irow = wrk->irow;
@@ -91,9 +91,9 @@ static void RescalerExportRowExpand(WebPRescaler* const wrk) {
const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
for (x_out = 0; x_out < max_span; x_out += 8) {
const uint32x4_t C0 =
- Interpolate(frow + x_out + 0, irow + x_out + 0, A, B);
+ Interpolate_NEON(frow + x_out + 0, irow + x_out + 0, A, B);
const uint32x4_t C1 =
- Interpolate(frow + x_out + 4, irow + x_out + 4, A, B);
+ Interpolate_NEON(frow + x_out + 4, irow + x_out + 4, A, B);
const uint32x4_t D0 = MULT_FIX(C0, fy_scale_half);
const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
const uint16x4_t E0 = vmovn_u32(D0);
@@ -112,7 +112,7 @@ static void RescalerExportRowExpand(WebPRescaler* const wrk) {
}
}
-static void RescalerExportRowShrink(WebPRescaler* const wrk) {
+static void RescalerExportRowShrink_NEON(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
rescaler_t* const irow = wrk->irow;
@@ -175,8 +175,8 @@ static void RescalerExportRowShrink(WebPRescaler* const wrk) {
extern void WebPRescalerDspInitNEON(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitNEON(void) {
- WebPRescalerExportRowExpand = RescalerExportRowExpand;
- WebPRescalerExportRowShrink = RescalerExportRowShrink;
+ WebPRescalerExportRowExpand = RescalerExportRowExpand_NEON;
+ WebPRescalerExportRowShrink = RescalerExportRowShrink_NEON;
}
#else // !WEBP_USE_NEON
diff --git a/media/libwebp/dsp/rescaler_sse2.c b/media/libwebp/dsp/rescaler_sse2.c
index 8271c22e0..1306f8457 100644
--- a/media/libwebp/dsp/rescaler_sse2.c
+++ b/media/libwebp/dsp/rescaler_sse2.c
@@ -11,9 +11,9 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
-#if defined(WEBP_USE_SSE2)
+#if defined(WEBP_USE_SSE2) && !defined(WEBP_REDUCE_SIZE)
#include <emmintrin.h>
#include <assert.h>
@@ -27,7 +27,7 @@
#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
-static void LoadTwoPixels(const uint8_t* const src, __m128i* out) {
+static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) {
const __m128i zero = _mm_setzero_si128();
const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
const __m128i B = _mm_unpacklo_epi8(A, zero); // A0B0C0D0E0F0G0H0
@@ -36,28 +36,30 @@ static void LoadTwoPixels(const uint8_t* const src, __m128i* out) {
}
// input: 8 bytes ABCDEFGH -> output: A0B0C0D0E0F0G0H0
-static void LoadHeightPixels(const uint8_t* const src, __m128i* out) {
+static void LoadEightPixels_SSE2(const uint8_t* const src, __m128i* out) {
const __m128i zero = _mm_setzero_si128();
const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
*out = _mm_unpacklo_epi8(A, zero);
}
-static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
- const uint8_t* src) {
+static void RescalerImportRowExpand_SSE2(WebPRescaler* const wrk,
+ const uint8_t* src) {
rescaler_t* frow = wrk->frow;
const rescaler_t* const frow_end = frow + wrk->dst_width * wrk->num_channels;
const int x_add = wrk->x_add;
int accum = x_add;
__m128i cur_pixels;
+ // SSE2 implementation only works with 16b signed arithmetic at max.
+ if (wrk->src_width < 8 || accum >= (1 << 15)) {
+ WebPRescalerImportRowExpand_C(wrk, src);
+ return;
+ }
+
assert(!WebPRescalerInputDone(wrk));
assert(wrk->x_expand);
if (wrk->num_channels == 4) {
- if (wrk->src_width < 2) {
- WebPRescalerImportRowExpandC(wrk, src);
- return;
- }
- LoadTwoPixels(src, &cur_pixels);
+ LoadTwoPixels_SSE2(src, &cur_pixels);
src += 4;
while (1) {
const __m128i mult = _mm_set1_epi32(((x_add - accum) << 16) | accum);
@@ -67,7 +69,7 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
if (frow >= frow_end) break;
accum -= wrk->x_sub;
if (accum < 0) {
- LoadTwoPixels(src, &cur_pixels);
+ LoadTwoPixels_SSE2(src, &cur_pixels);
src += 4;
accum += x_add;
}
@@ -75,11 +77,7 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
} else {
int left;
const uint8_t* const src_limit = src + wrk->src_width - 8;
- if (wrk->src_width < 8) {
- WebPRescalerImportRowExpandC(wrk, src);
- return;
- }
- LoadHeightPixels(src, &cur_pixels);
+ LoadEightPixels_SSE2(src, &cur_pixels);
src += 7;
left = 7;
while (1) {
@@ -94,7 +92,7 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
if (--left) {
cur_pixels = _mm_srli_si128(cur_pixels, 2);
} else if (src <= src_limit) {
- LoadHeightPixels(src, &cur_pixels);
+ LoadEightPixels_SSE2(src, &cur_pixels);
src += 7;
left = 7;
} else { // tail
@@ -110,8 +108,8 @@ static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
assert(accum == 0);
}
-static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
- const uint8_t* src) {
+static void RescalerImportRowShrink_SSE2(WebPRescaler* const wrk,
+ const uint8_t* src) {
const int x_sub = wrk->x_sub;
int accum = 0;
const __m128i zero = _mm_setzero_si128();
@@ -123,7 +121,7 @@ static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
const rescaler_t* const frow_end = wrk->frow + 4 * wrk->dst_width;
if (wrk->num_channels != 4 || wrk->x_add > (x_sub << 7)) {
- WebPRescalerImportRowShrinkC(wrk, src);
+ WebPRescalerImportRowShrink_C(wrk, src);
return;
}
assert(!WebPRescalerInputDone(wrk));
@@ -169,12 +167,12 @@ static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
// Row export
// load *src as epi64, multiply by mult and store result in [out0 ... out3]
-static WEBP_INLINE void LoadDispatchAndMult(const rescaler_t* const src,
- const __m128i* const mult,
- __m128i* const out0,
- __m128i* const out1,
- __m128i* const out2,
- __m128i* const out3) {
+static WEBP_INLINE void LoadDispatchAndMult_SSE2(const rescaler_t* const src,
+ const __m128i* const mult,
+ __m128i* const out0,
+ __m128i* const out1,
+ __m128i* const out2,
+ __m128i* const out3) {
const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + 0));
const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + 4));
const __m128i A2 = _mm_srli_epi64(A0, 32);
@@ -192,12 +190,12 @@ static WEBP_INLINE void LoadDispatchAndMult(const rescaler_t* const src,
}
}
-static WEBP_INLINE void ProcessRow(const __m128i* const A0,
- const __m128i* const A1,
- const __m128i* const A2,
- const __m128i* const A3,
- const __m128i* const mult,
- uint8_t* const dst) {
+static WEBP_INLINE void ProcessRow_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 rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
const __m128i B0 = _mm_mul_epu32(*A0, *mult);
@@ -210,7 +208,7 @@ static WEBP_INLINE void ProcessRow(const __m128i* const A0,
const __m128i C3 = _mm_add_epi64(B3, rounder);
const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX);
const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
-#if (WEBP_RESCALER_FIX < 32)
+#if (WEBP_RESCALER_RFIX < 32)
const __m128i D2 =
_mm_and_si128(_mm_slli_epi64(C2, 32 - WEBP_RESCALER_RFIX), mask);
const __m128i D3 =
@@ -226,7 +224,7 @@ static WEBP_INLINE void ProcessRow(const __m128i* const A0,
_mm_storel_epi64((__m128i*)dst, G);
}
-static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
+static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
rescaler_t* const irow = wrk->irow;
@@ -240,8 +238,8 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
if (wrk->y_accum == 0) {
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
__m128i A0, A1, A2, A3;
- LoadDispatchAndMult(frow + x_out, NULL, &A0, &A1, &A2, &A3);
- ProcessRow(&A0, &A1, &A2, &A3, &mult, dst + x_out);
+ LoadDispatchAndMult_SSE2(frow + x_out, NULL, &A0, &A1, &A2, &A3);
+ ProcessRow_SSE2(&A0, &A1, &A2, &A3, &mult, dst + x_out);
}
for (; x_out < x_out_max; ++x_out) {
const uint32_t J = frow[x_out];
@@ -257,8 +255,8 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
- LoadDispatchAndMult(frow + x_out, &mA, &A0, &A1, &A2, &A3);
- LoadDispatchAndMult(irow + x_out, &mB, &B0, &B1, &B2, &B3);
+ LoadDispatchAndMult_SSE2(frow + x_out, &mA, &A0, &A1, &A2, &A3);
+ LoadDispatchAndMult_SSE2(irow + x_out, &mB, &B0, &B1, &B2, &B3);
{
const __m128i C0 = _mm_add_epi64(A0, B0);
const __m128i C1 = _mm_add_epi64(A1, B1);
@@ -272,7 +270,7 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
const __m128i E1 = _mm_srli_epi64(D1, WEBP_RESCALER_RFIX);
const __m128i E2 = _mm_srli_epi64(D2, WEBP_RESCALER_RFIX);
const __m128i E3 = _mm_srli_epi64(D3, WEBP_RESCALER_RFIX);
- ProcessRow(&E0, &E1, &E2, &E3, &mult, dst + x_out);
+ ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult, dst + x_out);
}
}
for (; x_out < x_out_max; ++x_out) {
@@ -286,7 +284,7 @@ static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
}
}
-static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
+static void RescalerExportRowShrink_SSE2(WebPRescaler* const wrk) {
int x_out;
uint8_t* const dst = wrk->dst;
rescaler_t* const irow = wrk->irow;
@@ -303,8 +301,8 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
__m128i A0, A1, A2, A3, B0, B1, B2, B3;
- LoadDispatchAndMult(irow + x_out, NULL, &A0, &A1, &A2, &A3);
- LoadDispatchAndMult(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
+ LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
+ LoadDispatchAndMult_SSE2(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
{
const __m128i C0 = _mm_add_epi64(B0, rounder);
const __m128i C1 = _mm_add_epi64(B1, rounder);
@@ -324,7 +322,7 @@ static void RescalerExportRowShrinkSSE2(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(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
+ ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
}
}
for (; x_out < x_out_max; ++x_out) {
@@ -340,10 +338,10 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
const __m128i zero = _mm_setzero_si128();
for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
__m128i A0, A1, A2, A3;
- LoadDispatchAndMult(irow + x_out, NULL, &A0, &A1, &A2, &A3);
+ LoadDispatchAndMult_SSE2(irow + x_out, NULL, &A0, &A1, &A2, &A3);
_mm_storeu_si128((__m128i*)(irow + x_out + 0), zero);
_mm_storeu_si128((__m128i*)(irow + x_out + 4), zero);
- ProcessRow(&A0, &A1, &A2, &A3, &mult, dst + x_out);
+ ProcessRow_SSE2(&A0, &A1, &A2, &A3, &mult, dst + x_out);
}
for (; x_out < x_out_max; ++x_out) {
const int v = (int)MULT_FIX(irow[x_out], scale);
@@ -362,10 +360,10 @@ static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
extern void WebPRescalerDspInitSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitSSE2(void) {
- WebPRescalerImportRowExpand = RescalerImportRowExpandSSE2;
- WebPRescalerImportRowShrink = RescalerImportRowShrinkSSE2;
- WebPRescalerExportRowExpand = RescalerExportRowExpandSSE2;
- WebPRescalerExportRowShrink = RescalerExportRowShrinkSSE2;
+ WebPRescalerImportRowExpand = RescalerImportRowExpand_SSE2;
+ WebPRescalerImportRowShrink = RescalerImportRowShrink_SSE2;
+ WebPRescalerExportRowExpand = RescalerExportRowExpand_SSE2;
+ WebPRescalerExportRowShrink = RescalerExportRowShrink_SSE2;
}
#else // !WEBP_USE_SSE2
diff --git a/media/libwebp/dsp/upsampling.c b/media/libwebp/dsp/upsampling.c
index 265e722c1..b76483a3a 100644
--- a/media/libwebp/dsp/upsampling.c
+++ b/media/libwebp/dsp/upsampling.c
@@ -11,8 +11,8 @@
//
// Author: somnath@google.com (Somnath Banerjee)
-#include "./dsp.h"
-#include "./yuv.h"
+#include "../dsp/dsp.h"
+#include "../dsp/yuv.h"
#include <assert.h>
@@ -63,17 +63,17 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
- top_dst + (2 * x - 1) * XSTEP); \
+ top_dst + (2 * x - 1) * (XSTEP)); \
FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
- top_dst + (2 * x - 0) * XSTEP); \
+ top_dst + (2 * x - 0) * (XSTEP)); \
} \
if (bottom_y != NULL) { \
const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
const uint32_t uv1 = (diag_12 + uv) >> 1; \
FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
- bottom_dst + (2 * x - 1) * XSTEP); \
+ bottom_dst + (2 * x - 1) * (XSTEP)); \
FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \
- bottom_dst + (2 * x + 0) * XSTEP); \
+ bottom_dst + (2 * x + 0) * (XSTEP)); \
} \
tl_uv = t_uv; \
l_uv = uv; \
@@ -82,24 +82,50 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
{ \
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
- top_dst + (len - 1) * XSTEP); \
+ top_dst + (len - 1) * (XSTEP)); \
} \
if (bottom_y != NULL) { \
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
- bottom_dst + (len - 1) * XSTEP); \
+ bottom_dst + (len - 1) * (XSTEP)); \
} \
} \
}
// All variants implemented.
-UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
-UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
-UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
-UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
-UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
-UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
-UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
+#if !WEBP_NEON_OMIT_C_CODE
+UPSAMPLE_FUNC(UpsampleRgbaLinePair_C, VP8YuvToRgba, 4)
+UPSAMPLE_FUNC(UpsampleBgraLinePair_C, VP8YuvToBgra, 4)
+#if !defined(WEBP_REDUCE_CSP)
+UPSAMPLE_FUNC(UpsampleArgbLinePair_C, VP8YuvToArgb, 4)
+UPSAMPLE_FUNC(UpsampleRgbLinePair_C, VP8YuvToRgb, 3)
+UPSAMPLE_FUNC(UpsampleBgrLinePair_C, VP8YuvToBgr, 3)
+UPSAMPLE_FUNC(UpsampleRgba4444LinePair_C, VP8YuvToRgba4444, 2)
+UPSAMPLE_FUNC(UpsampleRgb565LinePair_C, VP8YuvToRgb565, 2)
+#else
+static void EmptyUpsampleFunc(const uint8_t* top_y, const uint8_t* bottom_y,
+ const uint8_t* top_u, const uint8_t* top_v,
+ const uint8_t* cur_u, const uint8_t* cur_v,
+ uint8_t* top_dst, uint8_t* bottom_dst, int len) {
+ (void)top_y;
+ (void)bottom_y;
+ (void)top_u;
+ (void)top_v;
+ (void)cur_u;
+ (void)cur_v;
+ (void)top_dst;
+ (void)bottom_dst;
+ (void)len;
+ assert(0); // COLORSPACE SUPPORT NOT COMPILED
+}
+#define UpsampleArgbLinePair_C EmptyUpsampleFunc
+#define UpsampleRgbLinePair_C EmptyUpsampleFunc
+#define UpsampleBgrLinePair_C EmptyUpsampleFunc
+#define UpsampleRgba4444LinePair_C EmptyUpsampleFunc
+#define UpsampleRgb565LinePair_C EmptyUpsampleFunc
+#endif // WEBP_REDUCE_CSP
+
+#endif
#undef LOAD_UV
#undef UPSAMPLE_FUNC
@@ -141,7 +167,6 @@ DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb)
WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
WebPInitUpsamplers();
- VP8YUVInit();
#ifdef FANCY_UPSAMPLING
return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB];
#else
@@ -158,16 +183,33 @@ extern void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
uint8_t* dst, int len) { \
int i; \
- for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
+ for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * (XSTEP)]); \
}
-YUV444_FUNC(WebPYuv444ToRgbC, VP8YuvToRgb, 3)
-YUV444_FUNC(WebPYuv444ToBgrC, VP8YuvToBgr, 3)
-YUV444_FUNC(WebPYuv444ToRgbaC, VP8YuvToRgba, 4)
-YUV444_FUNC(WebPYuv444ToBgraC, VP8YuvToBgra, 4)
-YUV444_FUNC(WebPYuv444ToArgbC, VP8YuvToArgb, 4)
-YUV444_FUNC(WebPYuv444ToRgba4444C, VP8YuvToRgba4444, 2)
-YUV444_FUNC(WebPYuv444ToRgb565C, VP8YuvToRgb565, 2)
+YUV444_FUNC(WebPYuv444ToRgba_C, VP8YuvToRgba, 4)
+YUV444_FUNC(WebPYuv444ToBgra_C, VP8YuvToBgra, 4)
+#if !defined(WEBP_REDUCE_CSP)
+YUV444_FUNC(WebPYuv444ToRgb_C, VP8YuvToRgb, 3)
+YUV444_FUNC(WebPYuv444ToBgr_C, VP8YuvToBgr, 3)
+YUV444_FUNC(WebPYuv444ToArgb_C, VP8YuvToArgb, 4)
+YUV444_FUNC(WebPYuv444ToRgba4444_C, VP8YuvToRgba4444, 2)
+YUV444_FUNC(WebPYuv444ToRgb565_C, VP8YuvToRgb565, 2)
+#else
+static void EmptyYuv444Func(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ (void)y;
+ (void)u;
+ (void)v;
+ (void)dst;
+ (void)len;
+}
+#define WebPYuv444ToRgb_C EmptyYuv444Func
+#define WebPYuv444ToBgr_C EmptyYuv444Func
+#define WebPYuv444ToArgb_C EmptyYuv444Func
+#define WebPYuv444ToRgba4444_C EmptyYuv444Func
+#define WebPYuv444ToRgb565_C EmptyYuv444Func
+#endif // WEBP_REDUCE_CSP
#undef YUV444_FUNC
@@ -175,24 +217,20 @@ WebPYUV444Converter WebPYUV444Converters[MODE_LAST];
extern void WebPInitYUV444ConvertersMIPSdspR2(void);
extern void WebPInitYUV444ConvertersSSE2(void);
-
-static volatile VP8CPUInfo upsampling_last_cpuinfo_used1 =
- (VP8CPUInfo)&upsampling_last_cpuinfo_used1;
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) {
- if (upsampling_last_cpuinfo_used1 == VP8GetCPUInfo) return;
-
- WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgbC;
- WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgbaC;
- WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgrC;
- WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgraC;
- WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgbC;
- WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444C;
- WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565C;
- WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgbaC;
- WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgraC;
- WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgbC;
- WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444C;
+extern void WebPInitYUV444ConvertersSSE41(void);
+
+WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) {
+ WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgba_C;
+ WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgra_C;
+ WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgb_C;
+ WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgr_C;
+ WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgb_C;
+ WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444_C;
+ WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565_C;
+ WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgba_C;
+ WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgra_C;
+ WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgb_C;
+ WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C;
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
@@ -200,41 +238,43 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) {
WebPInitYUV444ConvertersSSE2();
}
#endif
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ WebPInitYUV444ConvertersSSE41();
+ }
+#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
if (VP8GetCPUInfo(kMIPSdspR2)) {
WebPInitYUV444ConvertersMIPSdspR2();
}
#endif
}
- upsampling_last_cpuinfo_used1 = VP8GetCPUInfo;
}
//------------------------------------------------------------------------------
// Main calls
extern void WebPInitUpsamplersSSE2(void);
+extern void WebPInitUpsamplersSSE41(void);
extern void WebPInitUpsamplersNEON(void);
extern void WebPInitUpsamplersMIPSdspR2(void);
extern void WebPInitUpsamplersMSA(void);
-static volatile VP8CPUInfo upsampling_last_cpuinfo_used2 =
- (VP8CPUInfo)&upsampling_last_cpuinfo_used2;
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
- if (upsampling_last_cpuinfo_used2 == VP8GetCPUInfo) return;
-
+WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) {
#ifdef FANCY_UPSAMPLING
- WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
- WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
- WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
- WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
- WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
- WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
- WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
- WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
- WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
- WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
- WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+#if !WEBP_NEON_OMIT_C_CODE
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_C;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_C;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_C;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_C;
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_C;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_C;
+ WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_C;
+ WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_C;
+ WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_C;
+ WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_C;
+ WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_C;
+#endif
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
@@ -243,9 +283,9 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
WebPInitUpsamplersSSE2();
}
#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- WebPInitUpsamplersNEON();
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ WebPInitUpsamplersSSE41();
}
#endif
#if defined(WEBP_USE_MIPS_DSP_R2)
@@ -259,8 +299,29 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
}
#endif
}
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ WebPInitUpsamplersNEON();
+ }
+#endif
+
+ assert(WebPUpsamplers[MODE_RGBA] != NULL);
+ assert(WebPUpsamplers[MODE_BGRA] != NULL);
+ assert(WebPUpsamplers[MODE_rgbA] != NULL);
+ assert(WebPUpsamplers[MODE_bgrA] != NULL);
+#if !defined(WEBP_REDUCE_CSP) || !WEBP_NEON_OMIT_C_CODE
+ assert(WebPUpsamplers[MODE_RGB] != NULL);
+ assert(WebPUpsamplers[MODE_BGR] != NULL);
+ assert(WebPUpsamplers[MODE_ARGB] != NULL);
+ assert(WebPUpsamplers[MODE_RGBA_4444] != NULL);
+ assert(WebPUpsamplers[MODE_RGB_565] != NULL);
+ assert(WebPUpsamplers[MODE_Argb] != NULL);
+ assert(WebPUpsamplers[MODE_rgbA_4444] != NULL);
+#endif
+
#endif // FANCY_UPSAMPLING
- upsampling_last_cpuinfo_used2 = VP8GetCPUInfo;
}
//------------------------------------------------------------------------------
diff --git a/media/libwebp/dsp/upsampling_neon.c b/media/libwebp/dsp/upsampling_neon.c
index d371a834f..c847d70d4 100644
--- a/media/libwebp/dsp/upsampling_neon.c
+++ b/media/libwebp/dsp/upsampling_neon.c
@@ -12,15 +12,15 @@
// Author: mans@mansr.com (Mans Rullgard)
// Based on SSE code by: somnath@google.com (Somnath Banerjee)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_NEON)
#include <assert.h>
#include <arm_neon.h>
#include <string.h>
-#include "./neon.h"
-#include "./yuv.h"
+#include "../dsp/neon.h"
+#include "../dsp/yuv.h"
#ifdef FANCY_UPSAMPLING
@@ -58,8 +58,8 @@
} while (0)
// Turn the macro into a function for reducing code-size when non-critical
-static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
- uint8_t *out) {
+static void Upsample16Pixels_NEON(const uint8_t *r1, const uint8_t *r2,
+ uint8_t *out) {
UPSAMPLE_16PIXELS(r1, r2, out);
}
@@ -70,7 +70,7 @@ static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
/* replicate last byte */ \
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels)); \
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels)); \
- Upsample16Pixels(r1, r2, out); \
+ Upsample16Pixels_NEON(r1, r2, out); \
}
//-----------------------------------------------------------------------------
@@ -243,13 +243,15 @@ static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_y, \
}
// NEON variants of the fancy upsampler.
-NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair, Rgb, 3)
-NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair, Bgr, 3)
-NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair, Rgba, 4)
-NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair, Bgra, 4)
-NEON_UPSAMPLE_FUNC(UpsampleArgbLinePair, Argb, 4)
-NEON_UPSAMPLE_FUNC(UpsampleRgba4444LinePair, Rgba4444, 2)
-NEON_UPSAMPLE_FUNC(UpsampleRgb565LinePair, Rgb565, 2)
+NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair_NEON, Rgba, 4)
+NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair_NEON, Bgra, 4)
+#if !defined(WEBP_REDUCE_CSP)
+NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair_NEON, Rgb, 3)
+NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair_NEON, Bgr, 3)
+NEON_UPSAMPLE_FUNC(UpsampleArgbLinePair_NEON, Argb, 4)
+NEON_UPSAMPLE_FUNC(UpsampleRgba4444LinePair_NEON, Rgba4444, 2)
+NEON_UPSAMPLE_FUNC(UpsampleRgb565LinePair_NEON, Rgb565, 2)
+#endif // WEBP_REDUCE_CSP
//------------------------------------------------------------------------------
// Entry point
@@ -259,17 +261,19 @@ extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
extern void WebPInitUpsamplersNEON(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersNEON(void) {
- WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
- WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
- WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
- WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
- WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
- WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
- WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
- WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
- WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
- WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
- WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_NEON;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_NEON;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_NEON;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_NEON;
+#if !defined(WEBP_REDUCE_CSP)
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_NEON;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_NEON;
+ WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_NEON;
+ WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_NEON;
+ WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_NEON;
+ WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_NEON;
+ WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_NEON;
+#endif // WEBP_REDUCE_CSP
}
#endif // FANCY_UPSAMPLING
diff --git a/media/libwebp/dsp/upsampling_sse2.c b/media/libwebp/dsp/upsampling_sse2.c
index b5b668900..fd23681ca 100644
--- a/media/libwebp/dsp/upsampling_sse2.c
+++ b/media/libwebp/dsp/upsampling_sse2.c
@@ -11,14 +11,14 @@
//
// Author: somnath@google.com (Somnath Banerjee)
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#if defined(WEBP_USE_SSE2)
#include <assert.h>
#include <emmintrin.h>
#include <string.h>
-#include "./yuv.h"
+#include "../dsp/yuv.h"
#ifdef FANCY_UPSAMPLING
@@ -83,13 +83,13 @@
GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
\
/* pack the alternate pixels */ \
- PACK_AND_STORE(a, b, diag1, diag2, out + 0); /* store top */ \
- PACK_AND_STORE(c, d, diag2, diag1, out + 2 * 32); /* store bottom */ \
+ PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
+ PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
}
// Turn the macro into a function for reducing code-size when non-critical
-static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
- uint8_t* const out) {
+static void Upsample32Pixels_SSE2(const uint8_t r1[], const uint8_t r2[],
+ uint8_t* const out) {
UPSAMPLE_32PIXELS(r1, r2, out);
}
@@ -101,30 +101,15 @@ static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \
memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \
/* using the shared function instead of the macro saves ~3k code size */ \
- Upsample32Pixels(r1, r2, out); \
-}
-
-#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, \
- top_dst, bottom_dst, cur_x, num_pixels) { \
- int n; \
- for (n = 0; n < (num_pixels); ++n) { \
- FUNC(top_y[(cur_x) + n], r_u[n], r_v[n], \
- top_dst + ((cur_x) + n) * XSTEP); \
- } \
- if (bottom_y != NULL) { \
- for (n = 0; n < (num_pixels); ++n) { \
- FUNC(bottom_y[(cur_x) + n], r_u[64 + n], r_v[64 + n], \
- bottom_dst + ((cur_x) + n) * XSTEP); \
- } \
- } \
+ Upsample32Pixels_SSE2(r1, r2, out); \
}
#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
top_dst, bottom_dst, cur_x) do { \
- FUNC##32(top_y + (cur_x), r_u, r_v, top_dst + (cur_x) * XSTEP); \
- if (bottom_y != NULL) { \
- FUNC##32(bottom_y + (cur_x), r_u + 64, r_v + 64, \
- bottom_dst + (cur_x) * XSTEP); \
+ FUNC##32_SSE2((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \
+ if ((bottom_y) != NULL) { \
+ FUNC##32_SSE2((bottom_y) + (cur_x), r_u + 64, r_v + 64, \
+ (bottom_dst) + (cur_x) * (XSTEP)); \
} \
} while (0)
@@ -135,7 +120,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
int uv_pos, pos; \
/* 16byte-aligned array to cache reconstructed u and v */ \
- uint8_t uv_buf[4 * 32 + 15]; \
+ uint8_t uv_buf[14 * 32 + 15] = { 0 }; \
uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
uint8_t* const r_v = r_u + 32; \
\
@@ -160,22 +145,36 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
} \
if (len > 1) { \
const int left_over = ((len + 1) >> 1) - (pos >> 1); \
+ uint8_t* const tmp_top_dst = r_u + 4 * 32; \
+ uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \
+ uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \
+ uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \
assert(left_over > 0); \
UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
- CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, \
- pos, len - pos); \
+ memcpy(tmp_top, top_y + pos, len - pos); \
+ if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \
+ CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \
+ tmp_bottom_dst, 0); \
+ memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \
+ if (bottom_y != NULL) { \
+ memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \
+ (len - pos) * (XSTEP)); \
+ } \
} \
}
// SSE2 variants of the fancy upsampler.
-SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
-SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
-SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
-SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
-SSE2_UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
-SSE2_UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
-SSE2_UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair_SSE2, VP8YuvToRgba, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair_SSE2, VP8YuvToBgra, 4)
+
+#if !defined(WEBP_REDUCE_CSP)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE2, VP8YuvToRgb, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE2, VP8YuvToBgr, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleArgbLinePair_SSE2, VP8YuvToArgb, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleRgba4444LinePair_SSE2, VP8YuvToRgba4444, 2)
+SSE2_UPSAMPLE_FUNC(UpsampleRgb565LinePair_SSE2, VP8YuvToRgb565, 2)
+#endif // WEBP_REDUCE_CSP
#undef GET_M
#undef PACK_AND_STORE
@@ -193,17 +192,19 @@ extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
extern void WebPInitUpsamplersSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) {
- WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
- WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
- WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
- WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
- WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
- WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
- WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
- WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
- WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
- WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
- WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_SSE2;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_SSE2;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_SSE2;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_SSE2;
+#if !defined(WEBP_REDUCE_CSP)
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE2;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE2;
+ WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_SSE2;
+ WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_SSE2;
+ WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_SSE2;
+ WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_SSE2;
+ WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_SSE2;
+#endif // WEBP_REDUCE_CSP
}
#endif // FANCY_UPSAMPLING
@@ -213,29 +214,46 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) {
extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
extern void WebPInitYUV444ConvertersSSE2(void);
-#define YUV444_FUNC(FUNC_NAME, CALL, XSTEP) \
-extern void WebP##FUNC_NAME##C(const uint8_t* y, const uint8_t* u, \
- const uint8_t* v, uint8_t* dst, int len); \
+#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \
+extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len); \
static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
uint8_t* dst, int len) { \
int i; \
const int max_len = len & ~31; \
- for (i = 0; i < max_len; i += 32) CALL(y + i, u + i, v + i, dst + i * XSTEP);\
+ for (i = 0; i < max_len; i += 32) { \
+ CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \
+ } \
if (i < len) { /* C-fallback */ \
- WebP##FUNC_NAME##C(y + i, u + i, v + i, dst + i * XSTEP, len - i); \
+ CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \
} \
}
-YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba32, 4);
-YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra32, 4);
-YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb32, 3);
-YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr32, 3);
+YUV444_FUNC(Yuv444ToRgba_SSE2, VP8YuvToRgba32_SSE2, WebPYuv444ToRgba_C, 4);
+YUV444_FUNC(Yuv444ToBgra_SSE2, VP8YuvToBgra32_SSE2, WebPYuv444ToBgra_C, 4);
+#if !defined(WEBP_REDUCE_CSP)
+YUV444_FUNC(Yuv444ToRgb_SSE2, VP8YuvToRgb32_SSE2, WebPYuv444ToRgb_C, 3);
+YUV444_FUNC(Yuv444ToBgr_SSE2, VP8YuvToBgr32_SSE2, WebPYuv444ToBgr_C, 3);
+YUV444_FUNC(Yuv444ToArgb_SSE2, VP8YuvToArgb32_SSE2, WebPYuv444ToArgb_C, 4)
+YUV444_FUNC(Yuv444ToRgba4444_SSE2, VP8YuvToRgba444432_SSE2, \
+ WebPYuv444ToRgba4444_C, 2)
+YUV444_FUNC(Yuv444ToRgb565_SSE2, VP8YuvToRgb56532_SSE2, WebPYuv444ToRgb565_C, 2)
+#endif // WEBP_REDUCE_CSP
WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE2(void) {
- WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba;
- WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra;
- WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb;
- WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr;
+ WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba_SSE2;
+ WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra_SSE2;
+ WebPYUV444Converters[MODE_rgbA] = Yuv444ToRgba_SSE2;
+ WebPYUV444Converters[MODE_bgrA] = Yuv444ToBgra_SSE2;
+#if !defined(WEBP_REDUCE_CSP)
+ WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE2;
+ WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE2;
+ WebPYUV444Converters[MODE_ARGB] = Yuv444ToArgb_SSE2;
+ WebPYUV444Converters[MODE_RGBA_4444] = Yuv444ToRgba4444_SSE2;
+ WebPYUV444Converters[MODE_RGB_565] = Yuv444ToRgb565_SSE2;
+ WebPYUV444Converters[MODE_Argb] = Yuv444ToArgb_SSE2;
+ WebPYUV444Converters[MODE_rgbA_4444] = Yuv444ToRgba4444_SSE2;
+#endif // WEBP_REDUCE_CSP
}
#else
diff --git a/media/libwebp/dsp/upsampling_sse41.c b/media/libwebp/dsp/upsampling_sse41.c
new file mode 100644
index 000000000..65d175e87
--- /dev/null
+++ b/media/libwebp/dsp/upsampling_sse41.c
@@ -0,0 +1,239 @@
+// Copyright 2011 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.
+// -----------------------------------------------------------------------------
+//
+// SSE41 version of YUV to RGB upsampling functions.
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#include "../dsp/dsp.h"
+
+#if defined(WEBP_USE_SSE41)
+
+#include <assert.h>
+#include <smmintrin.h>
+#include <string.h>
+#include "../dsp/yuv.h"
+
+#ifdef FANCY_UPSAMPLING
+
+#if !defined(WEBP_REDUCE_CSP)
+
+// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows
+// u = (9*a + 3*b + 3*c + d + 8) / 16
+// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2
+// = (a + m + 1) / 2
+// where m = (a + 3*b + 3*c + d) / 8
+// = ((a + b + c + d) / 2 + b + c) / 4
+//
+// Let's say k = (a + b + c + d) / 4.
+// We can compute k as
+// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1
+// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2
+//
+// Then m can be written as
+// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1
+
+// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1
+#define GET_M(ij, in, out) do { \
+ const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \
+ const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \
+ const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \
+ const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\
+ const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \
+ (out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \
+} while (0)
+
+// pack and store two alternating pixel rows
+#define PACK_AND_STORE(a, b, da, db, out) do { \
+ const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
+ const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
+ const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \
+ const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \
+ _mm_store_si128(((__m128i*)(out)) + 0, t_1); \
+ _mm_store_si128(((__m128i*)(out)) + 1, t_2); \
+} while (0)
+
+// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
+#define UPSAMPLE_32PIXELS(r1, r2, out) { \
+ const __m128i one = _mm_set1_epi8(1); \
+ const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
+ const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
+ const __m128i c = _mm_loadu_si128((const __m128i*)&(r2)[0]); \
+ const __m128i d = _mm_loadu_si128((const __m128i*)&(r2)[1]); \
+ \
+ const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \
+ const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \
+ const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \
+ \
+ const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \
+ const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \
+ \
+ const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \
+ const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \
+ const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \
+ const __m128i t4 = _mm_avg_epu8(s, t); \
+ const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \
+ __m128i diag1, diag2; \
+ \
+ GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \
+ GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
+ \
+ /* pack the alternate pixels */ \
+ PACK_AND_STORE(a, b, diag1, diag2, (out) + 0); /* store top */ \
+ PACK_AND_STORE(c, d, diag2, diag1, (out) + 2 * 32); /* store bottom */ \
+}
+
+// Turn the macro into a function for reducing code-size when non-critical
+static void Upsample32Pixels_SSE41(const uint8_t r1[], const uint8_t r2[],
+ uint8_t* const out) {
+ UPSAMPLE_32PIXELS(r1, r2, out);
+}
+
+#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \
+ uint8_t r1[17], r2[17]; \
+ memcpy(r1, (tb), (num_pixels)); \
+ memcpy(r2, (bb), (num_pixels)); \
+ /* replicate last byte */ \
+ memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \
+ memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \
+ /* using the shared function instead of the macro saves ~3k code size */ \
+ Upsample32Pixels_SSE41(r1, r2, out); \
+}
+
+#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
+ top_dst, bottom_dst, cur_x) do { \
+ FUNC##32_SSE41((top_y) + (cur_x), r_u, r_v, (top_dst) + (cur_x) * (XSTEP)); \
+ if ((bottom_y) != NULL) { \
+ FUNC##32_SSE41((bottom_y) + (cur_x), r_u + 64, r_v + 64, \
+ (bottom_dst) + (cur_x) * (XSTEP)); \
+ } \
+} while (0)
+
+#define SSE4_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
+ const uint8_t* top_u, const uint8_t* top_v, \
+ const uint8_t* cur_u, const uint8_t* cur_v, \
+ uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
+ int uv_pos, pos; \
+ /* 16byte-aligned array to cache reconstructed u and v */ \
+ uint8_t uv_buf[14 * 32 + 15] = { 0 }; \
+ uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
+ uint8_t* const r_v = r_u + 32; \
+ \
+ assert(top_y != NULL); \
+ { /* Treat the first pixel in regular way */ \
+ const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
+ const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
+ const int u0_t = (top_u[0] + u_diag) >> 1; \
+ const int v0_t = (top_v[0] + v_diag) >> 1; \
+ FUNC(top_y[0], u0_t, v0_t, top_dst); \
+ if (bottom_y != NULL) { \
+ const int u0_b = (cur_u[0] + u_diag) >> 1; \
+ const int v0_b = (cur_v[0] + v_diag) >> 1; \
+ FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \
+ } \
+ } \
+ /* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \
+ for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \
+ UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \
+ UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \
+ CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \
+ } \
+ if (len > 1) { \
+ const int left_over = ((len + 1) >> 1) - (pos >> 1); \
+ uint8_t* const tmp_top_dst = r_u + 4 * 32; \
+ uint8_t* const tmp_bottom_dst = tmp_top_dst + 4 * 32; \
+ uint8_t* const tmp_top = tmp_bottom_dst + 4 * 32; \
+ uint8_t* const tmp_bottom = (bottom_y == NULL) ? NULL : tmp_top + 32; \
+ assert(left_over > 0); \
+ UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
+ UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
+ memcpy(tmp_top, top_y + pos, len - pos); \
+ if (bottom_y != NULL) memcpy(tmp_bottom, bottom_y + pos, len - pos); \
+ CONVERT2RGB_32(FUNC, XSTEP, tmp_top, tmp_bottom, tmp_top_dst, \
+ tmp_bottom_dst, 0); \
+ memcpy(top_dst + pos * (XSTEP), tmp_top_dst, (len - pos) * (XSTEP)); \
+ if (bottom_y != NULL) { \
+ memcpy(bottom_dst + pos * (XSTEP), tmp_bottom_dst, \
+ (len - pos) * (XSTEP)); \
+ } \
+ } \
+}
+
+// SSE4 variants of the fancy upsampler.
+SSE4_UPSAMPLE_FUNC(UpsampleRgbLinePair_SSE41, VP8YuvToRgb, 3)
+SSE4_UPSAMPLE_FUNC(UpsampleBgrLinePair_SSE41, VP8YuvToBgr, 3)
+
+#undef GET_M
+#undef PACK_AND_STORE
+#undef UPSAMPLE_32PIXELS
+#undef UPSAMPLE_LAST_BLOCK
+#undef CONVERT2RGB
+#undef CONVERT2RGB_32
+#undef SSE4_UPSAMPLE_FUNC
+
+#endif // WEBP_REDUCE_CSP
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
+
+extern void WebPInitUpsamplersSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE41(void) {
+#if !defined(WEBP_REDUCE_CSP)
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_SSE41;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_SSE41;
+#endif // WEBP_REDUCE_CSP
+}
+
+#endif // FANCY_UPSAMPLING
+
+//------------------------------------------------------------------------------
+
+extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
+extern void WebPInitYUV444ConvertersSSE41(void);
+
+#define YUV444_FUNC(FUNC_NAME, CALL, CALL_C, XSTEP) \
+extern void CALL_C(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len); \
+static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i; \
+ const int max_len = len & ~31; \
+ for (i = 0; i < max_len; i += 32) { \
+ CALL(y + i, u + i, v + i, dst + i * (XSTEP)); \
+ } \
+ if (i < len) { /* C-fallback */ \
+ CALL_C(y + i, u + i, v + i, dst + i * (XSTEP), len - i); \
+ } \
+}
+
+#if !defined(WEBP_REDUCE_CSP)
+YUV444_FUNC(Yuv444ToRgb_SSE41, VP8YuvToRgb32_SSE41, WebPYuv444ToRgb_C, 3);
+YUV444_FUNC(Yuv444ToBgr_SSE41, VP8YuvToBgr32_SSE41, WebPYuv444ToBgr_C, 3);
+#endif // WEBP_REDUCE_CSP
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE41(void) {
+#if !defined(WEBP_REDUCE_CSP)
+ WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb_SSE41;
+ WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr_SSE41;
+#endif // WEBP_REDUCE_CSP
+}
+
+#else
+
+WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersSSE41)
+
+#endif // WEBP_USE_SSE41
+
+#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_SSE41))
+WEBP_DSP_INIT_STUB(WebPInitUpsamplersSSE41)
+#endif
diff --git a/media/libwebp/dsp/yuv.c b/media/libwebp/dsp/yuv.c
index dd7d9dedf..12c04ca42 100644
--- a/media/libwebp/dsp/yuv.c
+++ b/media/libwebp/dsp/yuv.c
@@ -11,63 +11,11 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./yuv.h"
+#include "../dsp/yuv.h"
+#include <assert.h>
#include <stdlib.h>
-#if defined(WEBP_YUV_USE_TABLE)
-
-static int done = 0;
-
-static WEBP_INLINE uint8_t clip(int v, int max_value) {
- return v < 0 ? 0 : v > max_value ? max_value : v;
-}
-
-int16_t VP8kVToR[256], VP8kUToB[256];
-int32_t VP8kVToG[256], VP8kUToG[256];
-uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
-uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
-
-WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {
- int i;
- if (done) {
- return;
- }
-#ifndef USE_YUVj
- for (i = 0; i < 256; ++i) {
- VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
- VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
- VP8kVToG[i] = -45773 * (i - 128);
- VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
- }
- for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
- const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
- VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
- VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
- }
-#else
- for (i = 0; i < 256; ++i) {
- VP8kVToR[i] = (91881 * (i - 128) + YUV_HALF) >> YUV_FIX;
- VP8kUToG[i] = -22554 * (i - 128) + YUV_HALF;
- VP8kVToG[i] = -46802 * (i - 128);
- VP8kUToB[i] = (116130 * (i - 128) + YUV_HALF) >> YUV_FIX;
- }
- for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
- const int k = i;
- VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
- VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
- }
-#endif
-
- done = 1;
-}
-
-#else
-
-WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {}
-
-#endif // WEBP_YUV_USE_TABLE
-
//-----------------------------------------------------------------------------
// Plain-C version
@@ -75,14 +23,14 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {}
static void FUNC_NAME(const uint8_t* y, \
const uint8_t* u, const uint8_t* v, \
uint8_t* dst, int len) { \
- const uint8_t* const end = dst + (len & ~1) * XSTEP; \
+ const uint8_t* const end = dst + (len & ~1) * (XSTEP); \
while (dst != end) { \
FUNC(y[0], u[0], v[0], dst); \
- FUNC(y[1], u[0], v[0], dst + XSTEP); \
+ FUNC(y[1], u[0], v[0], dst + (XSTEP)); \
y += 2; \
++u; \
++v; \
- dst += 2 * XSTEP; \
+ dst += 2 * (XSTEP); \
} \
if (len & 1) { \
FUNC(y[0], u[0], v[0], dst); \
@@ -123,15 +71,11 @@ void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
WebPSamplerRowFunc WebPSamplers[MODE_LAST];
extern void WebPInitSamplersSSE2(void);
+extern void WebPInitSamplersSSE41(void);
extern void WebPInitSamplersMIPS32(void);
extern void WebPInitSamplersMIPSdspR2(void);
-static volatile VP8CPUInfo yuv_last_cpuinfo_used =
- (VP8CPUInfo)&yuv_last_cpuinfo_used;
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
- if (yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
-
+WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
WebPSamplers[MODE_RGB] = YuvToRgbRow;
WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
WebPSamplers[MODE_BGR] = YuvToBgrRow;
@@ -151,6 +95,11 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
WebPInitSamplersSSE2();
}
#endif // WEBP_USE_SSE2
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ WebPInitSamplersSSE41();
+ }
+#endif // WEBP_USE_SSE41
#if defined(WEBP_USE_MIPS32)
if (VP8GetCPUInfo(kMIPS32)) {
WebPInitSamplersMIPS32();
@@ -162,13 +111,12 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
}
#endif // WEBP_USE_MIPS_DSP_R2
}
- yuv_last_cpuinfo_used = VP8GetCPUInfo;
}
//-----------------------------------------------------------------------------
// ARGB -> YUV converters
-static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
+static void ConvertARGBToY_C(const uint32_t* argb, uint8_t* y, int width) {
int i;
for (i = 0; i < width; ++i) {
const uint32_t p = argb[i];
@@ -220,14 +168,14 @@ void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v,
//-----------------------------------------------------------------------------
-static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
+static void ConvertRGB24ToY_C(const uint8_t* rgb, uint8_t* y, int width) {
int i;
for (i = 0; i < width; ++i, rgb += 3) {
y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
}
}
-static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
+static void ConvertBGR24ToY_C(const uint8_t* bgr, uint8_t* y, int width) {
int i;
for (i = 0; i < width; ++i, bgr += 3) {
y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
@@ -246,6 +194,7 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
//-----------------------------------------------------------------------------
+#if !WEBP_NEON_OMIT_C_CODE
#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
static uint16_t clip_y(int v) {
return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
@@ -283,6 +232,7 @@ static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len,
out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
}
}
+#endif // !WEBP_NEON_OMIT_C_CODE
#undef MAX_Y
@@ -304,26 +254,26 @@ void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src,
void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len,
const uint16_t* best_y, uint16_t* out);
-static volatile VP8CPUInfo rgba_to_yuv_last_cpuinfo_used =
- (VP8CPUInfo)&rgba_to_yuv_last_cpuinfo_used;
-
extern void WebPInitConvertARGBToYUVSSE2(void);
+extern void WebPInitConvertARGBToYUVSSE41(void);
+extern void WebPInitConvertARGBToYUVNEON(void);
extern void WebPInitSharpYUVSSE2(void);
+extern void WebPInitSharpYUVNEON(void);
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) {
- if (rgba_to_yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
-
- WebPConvertARGBToY = ConvertARGBToY;
+WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
+ WebPConvertARGBToY = ConvertARGBToY_C;
WebPConvertARGBToUV = WebPConvertARGBToUV_C;
- WebPConvertRGB24ToY = ConvertRGB24ToY;
- WebPConvertBGR24ToY = ConvertBGR24ToY;
+ WebPConvertRGB24ToY = ConvertRGB24ToY_C;
+ WebPConvertBGR24ToY = ConvertBGR24ToY_C;
WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
+#if !WEBP_NEON_OMIT_C_CODE
WebPSharpYUVUpdateY = SharpYUVUpdateY_C;
WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C;
WebPSharpYUVFilterRow = SharpYUVFilterRow_C;
+#endif
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
@@ -332,6 +282,27 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) {
WebPInitSharpYUVSSE2();
}
#endif // WEBP_USE_SSE2
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ WebPInitConvertARGBToYUVSSE41();
+ }
+#endif // WEBP_USE_SSE41
+ }
+
+#if defined(WEBP_USE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE ||
+ (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
+ WebPInitConvertARGBToYUVNEON();
+ WebPInitSharpYUVNEON();
}
- rgba_to_yuv_last_cpuinfo_used = VP8GetCPUInfo;
+#endif // WEBP_USE_NEON
+
+ assert(WebPConvertARGBToY != NULL);
+ assert(WebPConvertARGBToUV != NULL);
+ assert(WebPConvertRGB24ToY != NULL);
+ assert(WebPConvertBGR24ToY != NULL);
+ assert(WebPConvertRGBA32ToUV != NULL);
+ assert(WebPSharpYUVUpdateY != NULL);
+ assert(WebPSharpYUVUpdateRGB != NULL);
+ assert(WebPSharpYUVFilterRow != NULL);
}
diff --git a/media/libwebp/dsp/yuv.h b/media/libwebp/dsp/yuv.h
index 1d33b5863..b4c5d0b6c 100644
--- a/media/libwebp/dsp/yuv.h
+++ b/media/libwebp/dsp/yuv.h
@@ -35,19 +35,9 @@
#ifndef WEBP_DSP_YUV_H_
#define WEBP_DSP_YUV_H_
-#include "./dsp.h"
+#include "../dsp/dsp.h"
#include "../dec/vp8_dec.h"
-#if defined(WEBP_EXPERIMENTAL_FEATURES)
-// Do NOT activate this feature for real compression. This is only experimental!
-// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
-// This colorspace is close to Rec.601's Y'CbCr model with the notable
-// difference of allowing larger range for luma/chroma.
-// See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
-// difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
-// #define USE_YUVj
-#endif
-
//------------------------------------------------------------------------------
// YUV -> RGB conversion
@@ -58,12 +48,8 @@ extern "C" {
enum {
YUV_FIX = 16, // fixed-point precision for RGB->YUV
YUV_HALF = 1 << (YUV_FIX - 1),
- YUV_MASK = (256 << YUV_FIX) - 1,
- YUV_RANGE_MIN = -227, // min value of r/g/b output
- YUV_RANGE_MAX = 256 + 226, // max value of r/g/b output
YUV_FIX2 = 6, // fixed-point precision for YUV->RGB
- YUV_HALF2 = 1 << YUV_FIX2 >> 1,
YUV_MASK2 = (256 << YUV_FIX2) - 1
};
@@ -111,7 +97,7 @@ static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
const int b = VP8YUVToB(y, u); // 5 usable bits
const int rg = (r & 0xf8) | (g >> 5);
const int gb = ((g << 3) & 0xe0) | (b >> 3);
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
rgb[0] = gb;
rgb[1] = rg;
#else
@@ -127,7 +113,7 @@ static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
const int b = VP8YUVToB(y, u); // 4 usable bits
const int rg = (r & 0xf0) | (g >> 4);
const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits
-#ifdef WEBP_SWAP_16BIT_CSP
+#if (WEBP_SWAP_16BIT_CSP == 1)
argb[0] = ba;
argb[1] = rg;
#else
@@ -157,32 +143,42 @@ static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
rgba[3] = 0xff;
}
-// Must be called before everything, to initialize the tables.
-void VP8YUVInit(void);
-
//-----------------------------------------------------------------------------
// SSE2 extra functions (mostly for upsampling_sse2.c)
#if defined(WEBP_USE_SSE2)
// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst.
-void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst);
-void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst);
-void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst);
-void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst);
-void VP8YuvToArgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst);
-void VP8YuvToRgba444432(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst);
-void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst);
+void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u,
+ const uint8_t* v, uint8_t* dst);
+void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
#endif // WEBP_USE_SSE2
+//-----------------------------------------------------------------------------
+// SSE41 extra functions (mostly for upsampling_sse41.c)
+
+#if defined(WEBP_USE_SSE41)
+
+// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst.
+void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+
+#endif // WEBP_USE_SSE41
+
//------------------------------------------------------------------------------
// RGB -> YUV conversion
@@ -192,8 +188,6 @@ static WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
}
-#ifndef USE_YUVj
-
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
const int luma = 16839 * r + 33059 * g + 6420 * b;
return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip
@@ -209,28 +203,6 @@ static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
return VP8ClipUV(v, rounding);
}
-#else
-
-// This JPEG-YUV colorspace, only for comparison!
-// These are also 16bit precision coefficients from Rec.601, but with full
-// [0..255] output range.
-static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
- const int luma = 19595 * r + 38470 * g + 7471 * b;
- return (luma + rounding) >> YUV_FIX; // no need to clip
-}
-
-static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
- const int u = -11058 * r - 21710 * g + 32768 * b;
- return VP8ClipUV(u, rounding);
-}
-
-static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
- const int v = 32768 * r - 27439 * g - 5329 * b;
- return VP8ClipUV(v, rounding);
-}
-
-#endif // USE_YUVj
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/media/libwebp/dsp/yuv_sse2.c b/media/libwebp/dsp/yuv_sse2.c
index e33c2bbaf..755662a05 100644
--- a/media/libwebp/dsp/yuv_sse2.c
+++ b/media/libwebp/dsp/yuv_sse2.c
@@ -11,11 +11,11 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./yuv.h"
+#include "../dsp/yuv.h"
#if defined(WEBP_USE_SSE2)
-#include "./common_sse2.h"
+#include "../dsp/common_sse2.h"
#include <stdlib.h>
#include <emmintrin.h>
@@ -26,12 +26,12 @@
// R = (19077 * y + 26149 * v - 14234) >> 6
// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6
// B = (19077 * y + 33050 * u - 17685) >> 6
-static void ConvertYUV444ToRGB(const __m128i* const Y0,
- const __m128i* const U0,
- const __m128i* const V0,
- __m128i* const R,
- __m128i* const G,
- __m128i* const B) {
+static void ConvertYUV444ToRGB_SSE2(const __m128i* const Y0,
+ const __m128i* const U0,
+ const __m128i* const V0,
+ __m128i* const R,
+ __m128i* const G,
+ __m128i* const B) {
const __m128i k19077 = _mm_set1_epi16(19077);
const __m128i k26149 = _mm_set1_epi16(26149);
const __m128i k14234 = _mm_set1_epi16(14234);
@@ -66,13 +66,13 @@ static void ConvertYUV444ToRGB(const __m128i* const Y0,
}
// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically.
-static WEBP_INLINE __m128i Load_HI_16(const uint8_t* src) {
+static WEBP_INLINE __m128i Load_HI_16_SSE2(const uint8_t* src) {
const __m128i zero = _mm_setzero_si128();
return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src));
}
// Load and replicate the U/V samples
-static WEBP_INLINE __m128i Load_UV_HI_8(const uint8_t* src) {
+static WEBP_INLINE __m128i Load_UV_HI_8_SSE2(const uint8_t* src) {
const __m128i zero = _mm_setzero_si128();
const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
@@ -80,29 +80,33 @@ static WEBP_INLINE __m128i Load_UV_HI_8(const uint8_t* src) {
}
// Convert 32 samples of YUV444 to R/G/B
-static void YUV444ToRGB(const uint8_t* const y,
- const uint8_t* const u,
- const uint8_t* const v,
- __m128i* const R, __m128i* const G, __m128i* const B) {
- const __m128i Y0 = Load_HI_16(y), U0 = Load_HI_16(u), V0 = Load_HI_16(v);
- ConvertYUV444ToRGB(&Y0, &U0, &V0, R, G, B);
+static void YUV444ToRGB_SSE2(const uint8_t* const y,
+ const uint8_t* const u,
+ const uint8_t* const v,
+ __m128i* const R, __m128i* const G,
+ __m128i* const B) {
+ const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_HI_16_SSE2(u),
+ V0 = Load_HI_16_SSE2(v);
+ ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B);
}
// Convert 32 samples of YUV420 to R/G/B
-static void YUV420ToRGB(const uint8_t* const y,
- const uint8_t* const u,
- const uint8_t* const v,
- __m128i* const R, __m128i* const G, __m128i* const B) {
- const __m128i Y0 = Load_HI_16(y), U0 = Load_UV_HI_8(u), V0 = Load_UV_HI_8(v);
- ConvertYUV444ToRGB(&Y0, &U0, &V0, R, G, B);
+static void YUV420ToRGB_SSE2(const uint8_t* const y,
+ const uint8_t* const u,
+ const uint8_t* const v,
+ __m128i* const R, __m128i* const G,
+ __m128i* const B) {
+ const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_UV_HI_8_SSE2(u),
+ V0 = Load_UV_HI_8_SSE2(v);
+ ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B);
}
// Pack R/G/B/A results into 32b output.
-static WEBP_INLINE void PackAndStore4(const __m128i* const R,
- const __m128i* const G,
- const __m128i* const B,
- const __m128i* const A,
- uint8_t* const dst) {
+static WEBP_INLINE void PackAndStore4_SSE2(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ const __m128i* const A,
+ uint8_t* const dst) {
const __m128i rb = _mm_packus_epi16(*R, *B);
const __m128i ga = _mm_packus_epi16(*G, *A);
const __m128i rg = _mm_unpacklo_epi8(rb, ga);
@@ -114,12 +118,12 @@ static WEBP_INLINE void PackAndStore4(const __m128i* const R,
}
// Pack R/G/B/A results into 16b output.
-static WEBP_INLINE void PackAndStore4444(const __m128i* const R,
- const __m128i* const G,
- const __m128i* const B,
- const __m128i* const A,
- uint8_t* const dst) {
-#if !defined(WEBP_SWAP_16BIT_CSP)
+static WEBP_INLINE void PackAndStore4444_SSE2(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ const __m128i* const A,
+ uint8_t* const dst) {
+#if (WEBP_SWAP_16BIT_CSP == 0)
const __m128i rg0 = _mm_packus_epi16(*R, *G);
const __m128i ba0 = _mm_packus_epi16(*B, *A);
#else
@@ -136,10 +140,10 @@ static WEBP_INLINE void PackAndStore4444(const __m128i* const R,
}
// Pack R/G/B results into 16b output.
-static WEBP_INLINE void PackAndStore565(const __m128i* const R,
- const __m128i* const G,
- const __m128i* const B,
- uint8_t* const dst) {
+static WEBP_INLINE void PackAndStore565_SSE2(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ uint8_t* const dst) {
const __m128i r0 = _mm_packus_epi16(*R, *R);
const __m128i g0 = _mm_packus_epi16(*G, *G);
const __m128i b0 = _mm_packus_epi16(*B, *B);
@@ -149,7 +153,7 @@ static WEBP_INLINE void PackAndStore565(const __m128i* const R,
const __m128i g2 = _mm_slli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0x1c)), 3);
const __m128i rg = _mm_or_si128(r1, g1);
const __m128i gb = _mm_or_si128(g2, b1);
-#if !defined(WEBP_SWAP_16BIT_CSP)
+#if (WEBP_SWAP_16BIT_CSP == 0)
const __m128i rgb565 = _mm_unpacklo_epi8(rg, gb);
#else
const __m128i rgb565 = _mm_unpacklo_epi8(gb, rg);
@@ -160,10 +164,10 @@ static WEBP_INLINE void PackAndStore565(const __m128i* const R,
// Pack the planar buffers
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
-static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1,
- __m128i* const in2, __m128i* const in3,
- __m128i* const in4, __m128i* const in5,
- uint8_t* const rgb) {
+static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1,
+ __m128i* const in2, __m128i* const in3,
+ __m128i* const in4, __m128i* const in5,
+ uint8_t* const rgb) {
// The input is 6 registers of sixteen 8b but for the sake of explanation,
// let's take 6 registers of four 8b values.
// To pack, we will keep taking one every two 8b integer and move it
@@ -176,7 +180,7 @@ static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1,
// Repeat the same permutations twice more:
// r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
// r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
- VP8PlanarTo24b(in0, in1, in2, in3, in4, in5);
+ VP8PlanarTo24b_SSE2(in0, in1, in2, in3, in4, in5);
_mm_storeu_si128((__m128i*)(rgb + 0), *in0);
_mm_storeu_si128((__m128i*)(rgb + 16), *in1);
@@ -186,69 +190,69 @@ static WEBP_INLINE void PlanarTo24b(__m128i* const in0, __m128i* const in1,
_mm_storeu_si128((__m128i*)(rgb + 80), *in5);
}
-void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToRgba32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n < 32; n += 8, dst += 32) {
__m128i R, G, B;
- YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
- PackAndStore4(&R, &G, &B, &kAlpha, dst);
+ YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
+ PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst);
}
}
-void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToBgra32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n < 32; n += 8, dst += 32) {
__m128i R, G, B;
- YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
- PackAndStore4(&B, &G, &R, &kAlpha, dst);
+ YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
+ PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst);
}
}
-void VP8YuvToArgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToArgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n < 32; n += 8, dst += 32) {
__m128i R, G, B;
- YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
- PackAndStore4(&kAlpha, &R, &G, &B, dst);
+ YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
+ PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst);
}
}
-void VP8YuvToRgba444432(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToRgba444432_SSE2(const uint8_t* y, const uint8_t* u,
+ const uint8_t* v, uint8_t* dst) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n < 32; n += 8, dst += 16) {
__m128i R, G, B;
- YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
- PackAndStore4444(&R, &G, &B, &kAlpha, dst);
+ YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
+ PackAndStore4444_SSE2(&R, &G, &B, &kAlpha, dst);
}
}
-void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToRgb56532_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
int n;
for (n = 0; n < 32; n += 8, dst += 16) {
__m128i R, G, B;
- YUV444ToRGB(y + n, u + n, v + n, &R, &G, &B);
- PackAndStore565(&R, &G, &B, dst);
+ YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
+ PackAndStore565_SSE2(&R, &G, &B, dst);
}
}
-void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToRgb32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
- YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
- YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1);
- YUV444ToRGB(y + 16, u + 16, v + 16, &R2, &G2, &B2);
- YUV444ToRGB(y + 24, u + 24, v + 24, &R3, &G3, &B3);
+ YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1);
+ YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2);
+ YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3);
// Cast to 8b and store as RRRRGGGGBBBB.
rgb0 = _mm_packus_epi16(R0, R1);
@@ -259,18 +263,18 @@ void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
rgb5 = _mm_packus_epi16(B2, B3);
// Pack as RGBRGBRGBRGB.
- PlanarTo24b(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
+ PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
}
-void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
+void VP8YuvToBgr32_SSE2(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
- YUV444ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
- YUV444ToRGB(y + 8, u + 8, v + 8, &R1, &G1, &B1);
- YUV444ToRGB(y + 16, u + 16, v + 16, &R2, &G2, &B2);
- YUV444ToRGB(y + 24, u + 24, v + 24, &R3, &G3, &B3);
+ YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1);
+ YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2);
+ YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3);
// Cast to 8b and store as BBBBGGGGRRRR.
bgr0 = _mm_packus_epi16(B0, B1);
@@ -281,20 +285,21 @@ void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
bgr5= _mm_packus_epi16(R2, R3);
// Pack as BGRBGRBGRBGR.
- PlanarTo24b(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
+ PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
}
//-----------------------------------------------------------------------------
// Arbitrary-length row conversion functions
-static void YuvToRgbaRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst, int len) {
+static void YuvToRgbaRow_SSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
__m128i R, G, B;
- YUV420ToRGB(y, u, v, &R, &G, &B);
- PackAndStore4(&R, &G, &B, &kAlpha, dst);
+ YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
+ PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst);
y += 8;
u += 4;
v += 4;
@@ -308,14 +313,15 @@ static void YuvToRgbaRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
}
}
-static void YuvToBgraRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst, int len) {
+static void YuvToBgraRow_SSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
__m128i R, G, B;
- YUV420ToRGB(y, u, v, &R, &G, &B);
- PackAndStore4(&B, &G, &R, &kAlpha, dst);
+ YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
+ PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst);
y += 8;
u += 4;
v += 4;
@@ -329,14 +335,15 @@ static void YuvToBgraRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
}
}
-static void YuvToArgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst, int len) {
+static void YuvToArgbRow_SSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
const __m128i kAlpha = _mm_set1_epi16(255);
int n;
for (n = 0; n + 8 <= len; n += 8, dst += 32) {
__m128i R, G, B;
- YUV420ToRGB(y, u, v, &R, &G, &B);
- PackAndStore4(&kAlpha, &R, &G, &B, dst);
+ YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
+ PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst);
y += 8;
u += 4;
v += 4;
@@ -350,17 +357,18 @@ static void YuvToArgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
}
}
-static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst, int len) {
+static void YuvToRgbRow_SSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
int n;
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
__m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
- YUV420ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
- YUV420ToRGB(y + 8, u + 4, v + 4, &R1, &G1, &B1);
- YUV420ToRGB(y + 16, u + 8, v + 8, &R2, &G2, &B2);
- YUV420ToRGB(y + 24, u + 12, v + 12, &R3, &G3, &B3);
+ YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1);
+ YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2);
+ YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3);
// Cast to 8b and store as RRRRGGGGBBBB.
rgb0 = _mm_packus_epi16(R0, R1);
@@ -371,7 +379,7 @@ static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
rgb5 = _mm_packus_epi16(B2, B3);
// Pack as RGBRGBRGBRGB.
- PlanarTo24b(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
+ PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
y += 32;
u += 16;
@@ -386,17 +394,18 @@ static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
}
}
-static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst, int len) {
+static void YuvToBgrRow_SSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
int n;
for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
__m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
__m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
- YUV420ToRGB(y + 0, u + 0, v + 0, &R0, &G0, &B0);
- YUV420ToRGB(y + 8, u + 4, v + 4, &R1, &G1, &B1);
- YUV420ToRGB(y + 16, u + 8, v + 8, &R2, &G2, &B2);
- YUV420ToRGB(y + 24, u + 12, v + 12, &R3, &G3, &B3);
+ YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1);
+ YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2);
+ YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3);
// Cast to 8b and store as BBBBGGGGRRRR.
bgr0 = _mm_packus_epi16(B0, B1);
@@ -407,7 +416,7 @@ static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
bgr5 = _mm_packus_epi16(R2, R3);
// Pack as BGRBGRBGRBGR.
- PlanarTo24b(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
+ PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
y += 32;
u += 16;
@@ -428,11 +437,11 @@ static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
extern void WebPInitSamplersSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
- WebPSamplers[MODE_RGB] = YuvToRgbRow;
- WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
- WebPSamplers[MODE_BGR] = YuvToBgrRow;
- WebPSamplers[MODE_BGRA] = YuvToBgraRow;
- WebPSamplers[MODE_ARGB] = YuvToArgbRow;
+ WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE2;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow_SSE2;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE2;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow_SSE2;
+ WebPSamplers[MODE_ARGB] = YuvToArgbRow_SSE2;
}
//------------------------------------------------------------------------------
@@ -445,7 +454,7 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
// Function that inserts a value of the second half of the in buffer in between
// every two char of the first half.
-static WEBP_INLINE void RGB24PackedToPlanarHelper(
+static WEBP_INLINE void RGB24PackedToPlanarHelper_SSE2(
const __m128i* const in /*in[6]*/, __m128i* const out /*out[6]*/) {
out[0] = _mm_unpacklo_epi8(in[0], in[3]);
out[1] = _mm_unpackhi_epi8(in[0], in[3]);
@@ -458,8 +467,8 @@ static WEBP_INLINE void RGB24PackedToPlanarHelper(
// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers:
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
// Similar to PlanarTo24bHelper(), but in reverse order.
-static WEBP_INLINE void RGB24PackedToPlanar(const uint8_t* const rgb,
- __m128i* const out /*out[6]*/) {
+static WEBP_INLINE void RGB24PackedToPlanar_SSE2(
+ const uint8_t* const rgb, __m128i* const out /*out[6]*/) {
__m128i tmp[6];
tmp[0] = _mm_loadu_si128((const __m128i*)(rgb + 0));
tmp[1] = _mm_loadu_si128((const __m128i*)(rgb + 16));
@@ -468,22 +477,22 @@ static WEBP_INLINE void RGB24PackedToPlanar(const uint8_t* const rgb,
tmp[4] = _mm_loadu_si128((const __m128i*)(rgb + 64));
tmp[5] = _mm_loadu_si128((const __m128i*)(rgb + 80));
- RGB24PackedToPlanarHelper(tmp, out);
- RGB24PackedToPlanarHelper(out, tmp);
- RGB24PackedToPlanarHelper(tmp, out);
- RGB24PackedToPlanarHelper(out, tmp);
- RGB24PackedToPlanarHelper(tmp, out);
+ RGB24PackedToPlanarHelper_SSE2(tmp, out);
+ RGB24PackedToPlanarHelper_SSE2(out, tmp);
+ RGB24PackedToPlanarHelper_SSE2(tmp, out);
+ RGB24PackedToPlanarHelper_SSE2(out, tmp);
+ RGB24PackedToPlanarHelper_SSE2(tmp, out);
}
// Convert 8 packed ARGB to r[], g[], b[]
-static WEBP_INLINE void RGB32PackedToPlanar(const uint32_t* const argb,
- __m128i* const rgb /*in[6]*/) {
+static WEBP_INLINE void RGB32PackedToPlanar_SSE2(const uint32_t* const argb,
+ __m128i* const rgb /*in[6]*/) {
const __m128i zero = _mm_setzero_si128();
__m128i a0 = LOAD_16(argb + 0);
__m128i a1 = LOAD_16(argb + 4);
__m128i a2 = LOAD_16(argb + 8);
__m128i a3 = LOAD_16(argb + 12);
- VP8L32bToPlanar(&a0, &a1, &a2, &a3);
+ VP8L32bToPlanar_SSE2(&a0, &a1, &a2, &a3);
rgb[0] = _mm_unpacklo_epi8(a1, zero);
rgb[1] = _mm_unpackhi_epi8(a1, zero);
rgb[2] = _mm_unpacklo_epi8(a2, zero);
@@ -511,10 +520,10 @@ static WEBP_INLINE void RGB32PackedToPlanar(const uint32_t* const argb,
} while (0)
#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
-static WEBP_INLINE void ConvertRGBToY(const __m128i* const R,
- const __m128i* const G,
- const __m128i* const B,
- __m128i* const Y) {
+static WEBP_INLINE void ConvertRGBToY_SSE2(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ __m128i* const Y) {
const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
const __m128i kGB_y = MK_CST_16(16384, 6420);
const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
@@ -526,10 +535,11 @@ static WEBP_INLINE void ConvertRGBToY(const __m128i* const R,
TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
}
-static WEBP_INLINE void ConvertRGBToUV(const __m128i* const R,
- const __m128i* const G,
- const __m128i* const B,
- __m128i* const U, __m128i* const V) {
+static WEBP_INLINE void ConvertRGBToUV_SSE2(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ __m128i* const U,
+ __m128i* const V) {
const __m128i kRG_u = MK_CST_16(-9719, -19081);
const __m128i kGB_u = MK_CST_16(0, 28800);
const __m128i kRG_v = MK_CST_16(28800, 0);
@@ -549,14 +559,14 @@ static WEBP_INLINE void ConvertRGBToUV(const __m128i* const R,
#undef MK_CST_16
#undef TRANSFORM
-static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
+static void ConvertRGB24ToY_SSE2(const uint8_t* rgb, uint8_t* y, int width) {
const int max_width = width & ~31;
int i;
for (i = 0; i < max_width; rgb += 3 * 16 * 2) {
__m128i rgb_plane[6];
int j;
- RGB24PackedToPlanar(rgb, rgb_plane);
+ RGB24PackedToPlanar_SSE2(rgb, rgb_plane);
for (j = 0; j < 2; ++j, i += 16) {
const __m128i zero = _mm_setzero_si128();
@@ -566,13 +576,13 @@ static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero);
g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero);
b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero);
- ConvertRGBToY(&r, &g, &b, &Y0);
+ ConvertRGBToY_SSE2(&r, &g, &b, &Y0);
// Convert to 16-bit Y.
r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero);
g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero);
b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero);
- ConvertRGBToY(&r, &g, &b, &Y1);
+ ConvertRGBToY_SSE2(&r, &g, &b, &Y1);
// Cast to 8-bit and store.
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
@@ -583,14 +593,14 @@ static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
}
}
-static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
+static void ConvertBGR24ToY_SSE2(const uint8_t* bgr, uint8_t* y, int width) {
const int max_width = width & ~31;
int i;
for (i = 0; i < max_width; bgr += 3 * 16 * 2) {
__m128i bgr_plane[6];
int j;
- RGB24PackedToPlanar(bgr, bgr_plane);
+ RGB24PackedToPlanar_SSE2(bgr, bgr_plane);
for (j = 0; j < 2; ++j, i += 16) {
const __m128i zero = _mm_setzero_si128();
@@ -600,13 +610,13 @@ static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero);
g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero);
r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero);
- ConvertRGBToY(&r, &g, &b, &Y0);
+ ConvertRGBToY_SSE2(&r, &g, &b, &Y0);
// Convert to 16-bit Y.
b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero);
g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero);
r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero);
- ConvertRGBToY(&r, &g, &b, &Y1);
+ ConvertRGBToY_SSE2(&r, &g, &b, &Y1);
// Cast to 8-bit and store.
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
@@ -617,14 +627,14 @@ static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
}
}
-static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
+static void ConvertARGBToY_SSE2(const uint32_t* argb, uint8_t* y, int width) {
const int max_width = width & ~15;
int i;
for (i = 0; i < max_width; i += 16) {
__m128i Y0, Y1, rgb[6];
- RGB32PackedToPlanar(&argb[i], rgb);
- ConvertRGBToY(&rgb[0], &rgb[2], &rgb[4], &Y0);
- ConvertRGBToY(&rgb[1], &rgb[3], &rgb[5], &Y1);
+ RGB32PackedToPlanar_SSE2(&argb[i], rgb);
+ ConvertRGBToY_SSE2(&rgb[0], &rgb[2], &rgb[4], &Y0);
+ ConvertRGBToY_SSE2(&rgb[1], &rgb[3], &rgb[5], &Y1);
STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
}
for (; i < width; ++i) { // left-over
@@ -636,31 +646,33 @@ static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
// Horizontal add (doubled) of two 16b values, result is 16b.
// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
-static void HorizontalAddPack(const __m128i* const A, const __m128i* const B,
- __m128i* const out) {
+static void HorizontalAddPack_SSE2(const __m128i* const A,
+ const __m128i* const B,
+ __m128i* const out) {
const __m128i k2 = _mm_set1_epi16(2);
const __m128i C = _mm_madd_epi16(*A, k2);
const __m128i D = _mm_madd_epi16(*B, k2);
*out = _mm_packs_epi32(C, D);
}
-static void ConvertARGBToUV(const uint32_t* argb, uint8_t* u, uint8_t* v,
- int src_width, int do_store) {
+static void ConvertARGBToUV_SSE2(const uint32_t* argb,
+ uint8_t* u, uint8_t* v,
+ int src_width, int do_store) {
const int max_width = src_width & ~31;
int i;
for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
__m128i rgb[6], U0, V0, U1, V1;
- RGB32PackedToPlanar(&argb[i], rgb);
- HorizontalAddPack(&rgb[0], &rgb[1], &rgb[0]);
- HorizontalAddPack(&rgb[2], &rgb[3], &rgb[2]);
- HorizontalAddPack(&rgb[4], &rgb[5], &rgb[4]);
- ConvertRGBToUV(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
-
- RGB32PackedToPlanar(&argb[i + 16], rgb);
- HorizontalAddPack(&rgb[0], &rgb[1], &rgb[0]);
- HorizontalAddPack(&rgb[2], &rgb[3], &rgb[2]);
- HorizontalAddPack(&rgb[4], &rgb[5], &rgb[4]);
- ConvertRGBToUV(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
+ RGB32PackedToPlanar_SSE2(&argb[i], rgb);
+ HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]);
+ HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]);
+ HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]);
+ ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
+
+ RGB32PackedToPlanar_SSE2(&argb[i + 16], rgb);
+ HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]);
+ HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]);
+ HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]);
+ ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
U0 = _mm_packus_epi16(U0, U1);
V0 = _mm_packus_epi16(V0, V1);
@@ -679,10 +691,9 @@ static void ConvertARGBToUV(const uint32_t* argb, uint8_t* u, uint8_t* v,
}
// Convert 16 packed ARGB 16b-values to r[], g[], b[]
-static WEBP_INLINE void RGBA32PackedToPlanar_16b(const uint16_t* const rgbx,
- __m128i* const r,
- __m128i* const g,
- __m128i* const b) {
+static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE2(
+ const uint16_t* const rgbx,
+ __m128i* const r, __m128i* const g, __m128i* const b) {
const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x
const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x
const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ...
@@ -701,16 +712,16 @@ static WEBP_INLINE void RGBA32PackedToPlanar_16b(const uint16_t* const rgbx,
*b = _mm_unpacklo_epi64(B1, B3);
}
-static void ConvertRGBA32ToUV(const uint16_t* rgb,
- uint8_t* u, uint8_t* v, int width) {
+static void ConvertRGBA32ToUV_SSE2(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width) {
const int max_width = width & ~15;
const uint16_t* const last_rgb = rgb + 4 * max_width;
while (rgb < last_rgb) {
__m128i r, g, b, U0, V0, U1, V1;
- RGBA32PackedToPlanar_16b(rgb + 0, &r, &g, &b);
- ConvertRGBToUV(&r, &g, &b, &U0, &V0);
- RGBA32PackedToPlanar_16b(rgb + 32, &r, &g, &b);
- ConvertRGBToUV(&r, &g, &b, &U1, &V1);
+ RGBA32PackedToPlanar_16b_SSE2(rgb + 0, &r, &g, &b);
+ ConvertRGBToUV_SSE2(&r, &g, &b, &U0, &V0);
+ RGBA32PackedToPlanar_16b_SSE2(rgb + 32, &r, &g, &b);
+ ConvertRGBToUV_SSE2(&r, &g, &b, &U1, &V1);
STORE_16(_mm_packus_epi16(U0, U1), u);
STORE_16(_mm_packus_epi16(V0, V1), v);
u += 16;
@@ -727,13 +738,13 @@ static void ConvertRGBA32ToUV(const uint16_t* rgb,
extern void WebPInitConvertARGBToYUVSSE2(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
- WebPConvertARGBToY = ConvertARGBToY;
- WebPConvertARGBToUV = ConvertARGBToUV;
+ WebPConvertARGBToY = ConvertARGBToY_SSE2;
+ WebPConvertARGBToUV = ConvertARGBToUV_SSE2;
- WebPConvertRGB24ToY = ConvertRGB24ToY;
- WebPConvertBGR24ToY = ConvertBGR24ToY;
+ WebPConvertRGB24ToY = ConvertRGB24ToY_SSE2;
+ WebPConvertBGR24ToY = ConvertBGR24ToY_SSE2;
- WebPConvertRGBA32ToUV = ConvertRGBA32ToUV;
+ WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2;
}
//------------------------------------------------------------------------------
diff --git a/media/libwebp/dsp/yuv_sse41.c b/media/libwebp/dsp/yuv_sse41.c
new file mode 100644
index 000000000..95ab7ad14
--- /dev/null
+++ b/media/libwebp/dsp/yuv_sse41.c
@@ -0,0 +1,613 @@
+// Copyright 2014 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.
+// -----------------------------------------------------------------------------
+//
+// YUV->RGB conversion functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "../dsp/yuv.h"
+
+#if defined(WEBP_USE_SSE41)
+
+#include "../dsp/common_sse41.h"
+#include <stdlib.h>
+#include <smmintrin.h>
+
+//-----------------------------------------------------------------------------
+// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
+
+// These constants are 14b fixed-point version of ITU-R BT.601 constants.
+// R = (19077 * y + 26149 * v - 14234) >> 6
+// G = (19077 * y - 6419 * u - 13320 * v + 8708) >> 6
+// B = (19077 * y + 33050 * u - 17685) >> 6
+static void ConvertYUV444ToRGB_SSE41(const __m128i* const Y0,
+ const __m128i* const U0,
+ const __m128i* const V0,
+ __m128i* const R,
+ __m128i* const G,
+ __m128i* const B) {
+ const __m128i k19077 = _mm_set1_epi16(19077);
+ const __m128i k26149 = _mm_set1_epi16(26149);
+ const __m128i k14234 = _mm_set1_epi16(14234);
+ // 33050 doesn't fit in a signed short: only use this with unsigned arithmetic
+ const __m128i k33050 = _mm_set1_epi16((short)33050);
+ const __m128i k17685 = _mm_set1_epi16(17685);
+ const __m128i k6419 = _mm_set1_epi16(6419);
+ const __m128i k13320 = _mm_set1_epi16(13320);
+ const __m128i k8708 = _mm_set1_epi16(8708);
+
+ const __m128i Y1 = _mm_mulhi_epu16(*Y0, k19077);
+
+ const __m128i R0 = _mm_mulhi_epu16(*V0, k26149);
+ const __m128i R1 = _mm_sub_epi16(Y1, k14234);
+ const __m128i R2 = _mm_add_epi16(R1, R0);
+
+ const __m128i G0 = _mm_mulhi_epu16(*U0, k6419);
+ const __m128i G1 = _mm_mulhi_epu16(*V0, k13320);
+ const __m128i G2 = _mm_add_epi16(Y1, k8708);
+ const __m128i G3 = _mm_add_epi16(G0, G1);
+ const __m128i G4 = _mm_sub_epi16(G2, G3);
+
+ // be careful with the saturated *unsigned* arithmetic here!
+ const __m128i B0 = _mm_mulhi_epu16(*U0, k33050);
+ const __m128i B1 = _mm_adds_epu16(B0, Y1);
+ const __m128i B2 = _mm_subs_epu16(B1, k17685);
+
+ // use logical shift for B2, which can be larger than 32767
+ *R = _mm_srai_epi16(R2, 6); // range: [-14234, 30815]
+ *G = _mm_srai_epi16(G4, 6); // range: [-10953, 27710]
+ *B = _mm_srli_epi16(B2, 6); // range: [0, 34238]
+}
+
+// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically.
+static WEBP_INLINE __m128i Load_HI_16_SSE41(const uint8_t* src) {
+ const __m128i zero = _mm_setzero_si128();
+ return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src));
+}
+
+// Load and replicate the U/V samples
+static WEBP_INLINE __m128i Load_UV_HI_8_SSE41(const uint8_t* src) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i tmp0 = _mm_cvtsi32_si128(*(const uint32_t*)src);
+ const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
+ return _mm_unpacklo_epi16(tmp1, tmp1); // replicate samples
+}
+
+// Convert 32 samples of YUV444 to R/G/B
+static void YUV444ToRGB_SSE41(const uint8_t* const y,
+ const uint8_t* const u,
+ const uint8_t* const v,
+ __m128i* const R, __m128i* const G,
+ __m128i* const B) {
+ const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_HI_16_SSE41(u),
+ V0 = Load_HI_16_SSE41(v);
+ ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B);
+}
+
+// Convert 32 samples of YUV420 to R/G/B
+static void YUV420ToRGB_SSE41(const uint8_t* const y,
+ const uint8_t* const u,
+ const uint8_t* const v,
+ __m128i* const R, __m128i* const G,
+ __m128i* const B) {
+ const __m128i Y0 = Load_HI_16_SSE41(y), U0 = Load_UV_HI_8_SSE41(u),
+ V0 = Load_UV_HI_8_SSE41(v);
+ ConvertYUV444ToRGB_SSE41(&Y0, &U0, &V0, R, G, B);
+}
+
+// Pack the planar buffers
+// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
+// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
+static WEBP_INLINE void PlanarTo24b_SSE41(
+ __m128i* const in0, __m128i* const in1, __m128i* const in2,
+ __m128i* const in3, __m128i* const in4, __m128i* const in5,
+ uint8_t* const rgb) {
+ // The input is 6 registers of sixteen 8b but for the sake of explanation,
+ // let's take 6 registers of four 8b values.
+ // To pack, we will keep taking one every two 8b integer and move it
+ // around as follows:
+ // Input:
+ // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7
+ // Split the 6 registers in two sets of 3 registers: the first set as the even
+ // 8b bytes, the second the odd ones:
+ // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7
+ // Repeat the same permutations twice more:
+ // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
+ // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
+ VP8PlanarTo24b_SSE41(in0, in1, in2, in3, in4, in5);
+
+ _mm_storeu_si128((__m128i*)(rgb + 0), *in0);
+ _mm_storeu_si128((__m128i*)(rgb + 16), *in1);
+ _mm_storeu_si128((__m128i*)(rgb + 32), *in2);
+ _mm_storeu_si128((__m128i*)(rgb + 48), *in3);
+ _mm_storeu_si128((__m128i*)(rgb + 64), *in4);
+ _mm_storeu_si128((__m128i*)(rgb + 80), *in5);
+}
+
+void VP8YuvToRgb32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
+ __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
+
+ YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1);
+ YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2);
+ YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3);
+
+ // Cast to 8b and store as RRRRGGGGBBBB.
+ rgb0 = _mm_packus_epi16(R0, R1);
+ rgb1 = _mm_packus_epi16(R2, R3);
+ rgb2 = _mm_packus_epi16(G0, G1);
+ rgb3 = _mm_packus_epi16(G2, G3);
+ rgb4 = _mm_packus_epi16(B0, B1);
+ rgb5 = _mm_packus_epi16(B2, B3);
+
+ // Pack as RGBRGBRGBRGB.
+ PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
+}
+
+void VP8YuvToBgr32_SSE41(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
+ __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
+
+ YUV444ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV444ToRGB_SSE41(y + 8, u + 8, v + 8, &R1, &G1, &B1);
+ YUV444ToRGB_SSE41(y + 16, u + 16, v + 16, &R2, &G2, &B2);
+ YUV444ToRGB_SSE41(y + 24, u + 24, v + 24, &R3, &G3, &B3);
+
+ // Cast to 8b and store as BBBBGGGGRRRR.
+ bgr0 = _mm_packus_epi16(B0, B1);
+ bgr1 = _mm_packus_epi16(B2, B3);
+ bgr2 = _mm_packus_epi16(G0, G1);
+ bgr3 = _mm_packus_epi16(G2, G3);
+ bgr4 = _mm_packus_epi16(R0, R1);
+ bgr5= _mm_packus_epi16(R2, R3);
+
+ // Pack as BGRBGRBGRBGR.
+ PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
+}
+
+//-----------------------------------------------------------------------------
+// Arbitrary-length row conversion functions
+
+static void YuvToRgbRow_SSE41(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
+ __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
+ __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
+
+ YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1);
+ YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2);
+ YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3);
+
+ // Cast to 8b and store as RRRRGGGGBBBB.
+ rgb0 = _mm_packus_epi16(R0, R1);
+ rgb1 = _mm_packus_epi16(R2, R3);
+ rgb2 = _mm_packus_epi16(G0, G1);
+ rgb3 = _mm_packus_epi16(G2, G3);
+ rgb4 = _mm_packus_epi16(B0, B1);
+ rgb5 = _mm_packus_epi16(B2, B3);
+
+ // Pack as RGBRGBRGBRGB.
+ PlanarTo24b_SSE41(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
+
+ y += 32;
+ u += 16;
+ v += 16;
+ }
+ for (; n < len; ++n) { // Finish off
+ VP8YuvToRgb(y[0], u[0], v[0], dst);
+ dst += 3;
+ y += 1;
+ u += (n & 1);
+ v += (n & 1);
+ }
+}
+
+static void YuvToBgrRow_SSE41(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
+ __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
+ __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
+
+ YUV420ToRGB_SSE41(y + 0, u + 0, v + 0, &R0, &G0, &B0);
+ YUV420ToRGB_SSE41(y + 8, u + 4, v + 4, &R1, &G1, &B1);
+ YUV420ToRGB_SSE41(y + 16, u + 8, v + 8, &R2, &G2, &B2);
+ YUV420ToRGB_SSE41(y + 24, u + 12, v + 12, &R3, &G3, &B3);
+
+ // Cast to 8b and store as BBBBGGGGRRRR.
+ bgr0 = _mm_packus_epi16(B0, B1);
+ bgr1 = _mm_packus_epi16(B2, B3);
+ bgr2 = _mm_packus_epi16(G0, G1);
+ bgr3 = _mm_packus_epi16(G2, G3);
+ bgr4 = _mm_packus_epi16(R0, R1);
+ bgr5 = _mm_packus_epi16(R2, R3);
+
+ // Pack as BGRBGRBGRBGR.
+ PlanarTo24b_SSE41(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
+
+ y += 32;
+ u += 16;
+ v += 16;
+ }
+ for (; n < len; ++n) { // Finish off
+ VP8YuvToBgr(y[0], u[0], v[0], dst);
+ dst += 3;
+ y += 1;
+ u += (n & 1);
+ v += (n & 1);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitSamplersSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE41(void) {
+ WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE41;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE41;
+}
+
+//------------------------------------------------------------------------------
+// RGB24/32 -> YUV converters
+
+// Load eight 16b-words from *src.
+#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src))
+// Store either 16b-words into *dst
+#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V))
+
+#define WEBP_SSE41_SHUFF(OUT) do { \
+ const __m128i tmp0 = _mm_shuffle_epi8(A0, shuff0); \
+ const __m128i tmp1 = _mm_shuffle_epi8(A1, shuff1); \
+ const __m128i tmp2 = _mm_shuffle_epi8(A2, shuff2); \
+ const __m128i tmp3 = _mm_shuffle_epi8(A3, shuff0); \
+ const __m128i tmp4 = _mm_shuffle_epi8(A4, shuff1); \
+ const __m128i tmp5 = _mm_shuffle_epi8(A5, shuff2); \
+ \
+ /* OR everything to get one channel */ \
+ const __m128i tmp6 = _mm_or_si128(tmp0, tmp1); \
+ const __m128i tmp7 = _mm_or_si128(tmp3, tmp4); \
+ out[OUT + 0] = _mm_or_si128(tmp6, tmp2); \
+ out[OUT + 1] = _mm_or_si128(tmp7, tmp5); \
+} while (0);
+
+// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers:
+// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
+// Similar to PlanarTo24bHelper(), but in reverse order.
+static WEBP_INLINE void RGB24PackedToPlanar_SSE41(
+ const uint8_t* const rgb, __m128i* const out /*out[6]*/) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)(rgb + 0));
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)(rgb + 16));
+ const __m128i A2 = _mm_loadu_si128((const __m128i*)(rgb + 32));
+ const __m128i A3 = _mm_loadu_si128((const __m128i*)(rgb + 48));
+ const __m128i A4 = _mm_loadu_si128((const __m128i*)(rgb + 64));
+ const __m128i A5 = _mm_loadu_si128((const __m128i*)(rgb + 80));
+
+ // Compute RR.
+ {
+ const __m128i shuff0 = _mm_set_epi8(
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0);
+ const __m128i shuff1 = _mm_set_epi8(
+ -1, -1, -1, -1, -1, 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1);
+ const __m128i shuff2 = _mm_set_epi8(
+ 13, 10, 7, 4, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
+ WEBP_SSE41_SHUFF(0)
+ }
+ // Compute GG.
+ {
+ const __m128i shuff0 = _mm_set_epi8(
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1);
+ const __m128i shuff1 = _mm_set_epi8(
+ -1, -1, -1, -1, -1, 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1);
+ const __m128i shuff2 = _mm_set_epi8(
+ 14, 11, 8, 5, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
+ WEBP_SSE41_SHUFF(2)
+ }
+ // Compute BB.
+ {
+ const __m128i shuff0 = _mm_set_epi8(
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, 11, 8, 5, 2);
+ const __m128i shuff1 = _mm_set_epi8(
+ -1, -1, -1, -1, -1, -1, 13, 10, 7, 4, 1, -1, -1, -1, -1, -1);
+ const __m128i shuff2 = _mm_set_epi8(
+ 15, 12, 9, 6, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
+ WEBP_SSE41_SHUFF(4)
+ }
+}
+
+#undef WEBP_SSE41_SHUFF
+
+// Convert 8 packed ARGB to r[], g[], b[]
+static WEBP_INLINE void RGB32PackedToPlanar_SSE41(
+ const uint32_t* const argb, __m128i* const rgb /*in[6]*/) {
+ const __m128i zero = _mm_setzero_si128();
+ __m128i a0 = LOAD_16(argb + 0);
+ __m128i a1 = LOAD_16(argb + 4);
+ __m128i a2 = LOAD_16(argb + 8);
+ __m128i a3 = LOAD_16(argb + 12);
+ VP8L32bToPlanar_SSE41(&a0, &a1, &a2, &a3);
+ rgb[0] = _mm_unpacklo_epi8(a1, zero);
+ rgb[1] = _mm_unpackhi_epi8(a1, zero);
+ rgb[2] = _mm_unpacklo_epi8(a2, zero);
+ rgb[3] = _mm_unpackhi_epi8(a2, zero);
+ rgb[4] = _mm_unpacklo_epi8(a3, zero);
+ rgb[5] = _mm_unpackhi_epi8(a3, zero);
+}
+
+// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX
+// It's a macro and not a function because we need to use immediate values with
+// srai_epi32, e.g.
+#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, \
+ ROUNDER, DESCALE_FIX, OUT) do { \
+ const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG); \
+ const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG); \
+ const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB); \
+ const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB); \
+ const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo); \
+ const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi); \
+ const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER); \
+ const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER); \
+ const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX); \
+ const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX); \
+ (OUT) = _mm_packs_epi32(V5_lo, V5_hi); \
+} while (0)
+
+#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
+static WEBP_INLINE void ConvertRGBToY_SSE41(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ __m128i* const Y) {
+ const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
+ const __m128i kGB_y = MK_CST_16(16384, 6420);
+ const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
+
+ const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
+ const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
+ const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
+ const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
+ TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
+}
+
+static WEBP_INLINE void ConvertRGBToUV_SSE41(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ __m128i* const U,
+ __m128i* const V) {
+ const __m128i kRG_u = MK_CST_16(-9719, -19081);
+ const __m128i kGB_u = MK_CST_16(0, 28800);
+ const __m128i kRG_v = MK_CST_16(28800, 0);
+ const __m128i kGB_v = MK_CST_16(-24116, -4684);
+ const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2);
+
+ const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
+ const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
+ const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
+ const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
+ TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u,
+ kHALF_UV, YUV_FIX + 2, *U);
+ TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v,
+ kHALF_UV, YUV_FIX + 2, *V);
+}
+
+#undef MK_CST_16
+#undef TRANSFORM
+
+static void ConvertRGB24ToY_SSE41(const uint8_t* rgb, uint8_t* y, int width) {
+ const int max_width = width & ~31;
+ int i;
+ for (i = 0; i < max_width; rgb += 3 * 16 * 2) {
+ __m128i rgb_plane[6];
+ int j;
+
+ RGB24PackedToPlanar_SSE41(rgb, rgb_plane);
+
+ for (j = 0; j < 2; ++j, i += 16) {
+ const __m128i zero = _mm_setzero_si128();
+ __m128i r, g, b, Y0, Y1;
+
+ // Convert to 16-bit Y.
+ r = _mm_unpacklo_epi8(rgb_plane[0 + j], zero);
+ g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero);
+ b = _mm_unpacklo_epi8(rgb_plane[4 + j], zero);
+ ConvertRGBToY_SSE41(&r, &g, &b, &Y0);
+
+ // Convert to 16-bit Y.
+ r = _mm_unpackhi_epi8(rgb_plane[0 + j], zero);
+ g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero);
+ b = _mm_unpackhi_epi8(rgb_plane[4 + j], zero);
+ ConvertRGBToY_SSE41(&r, &g, &b, &Y1);
+
+ // Cast to 8-bit and store.
+ STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
+ }
+ }
+ for (; i < width; ++i, rgb += 3) { // left-over
+ y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
+ }
+}
+
+static void ConvertBGR24ToY_SSE41(const uint8_t* bgr, uint8_t* y, int width) {
+ const int max_width = width & ~31;
+ int i;
+ for (i = 0; i < max_width; bgr += 3 * 16 * 2) {
+ __m128i bgr_plane[6];
+ int j;
+
+ RGB24PackedToPlanar_SSE41(bgr, bgr_plane);
+
+ for (j = 0; j < 2; ++j, i += 16) {
+ const __m128i zero = _mm_setzero_si128();
+ __m128i r, g, b, Y0, Y1;
+
+ // Convert to 16-bit Y.
+ b = _mm_unpacklo_epi8(bgr_plane[0 + j], zero);
+ g = _mm_unpacklo_epi8(bgr_plane[2 + j], zero);
+ r = _mm_unpacklo_epi8(bgr_plane[4 + j], zero);
+ ConvertRGBToY_SSE41(&r, &g, &b, &Y0);
+
+ // Convert to 16-bit Y.
+ b = _mm_unpackhi_epi8(bgr_plane[0 + j], zero);
+ g = _mm_unpackhi_epi8(bgr_plane[2 + j], zero);
+ r = _mm_unpackhi_epi8(bgr_plane[4 + j], zero);
+ ConvertRGBToY_SSE41(&r, &g, &b, &Y1);
+
+ // Cast to 8-bit and store.
+ STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
+ }
+ }
+ for (; i < width; ++i, bgr += 3) { // left-over
+ y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
+ }
+}
+
+static void ConvertARGBToY_SSE41(const uint32_t* argb, uint8_t* y, int width) {
+ const int max_width = width & ~15;
+ int i;
+ for (i = 0; i < max_width; i += 16) {
+ __m128i Y0, Y1, rgb[6];
+ RGB32PackedToPlanar_SSE41(&argb[i], rgb);
+ ConvertRGBToY_SSE41(&rgb[0], &rgb[2], &rgb[4], &Y0);
+ ConvertRGBToY_SSE41(&rgb[1], &rgb[3], &rgb[5], &Y1);
+ STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
+ }
+ for (; i < width; ++i) { // left-over
+ const uint32_t p = argb[i];
+ y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff,
+ YUV_HALF);
+ }
+}
+
+// Horizontal add (doubled) of two 16b values, result is 16b.
+// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
+static void HorizontalAddPack_SSE41(const __m128i* const A,
+ const __m128i* const B,
+ __m128i* const out) {
+ const __m128i k2 = _mm_set1_epi16(2);
+ const __m128i C = _mm_madd_epi16(*A, k2);
+ const __m128i D = _mm_madd_epi16(*B, k2);
+ *out = _mm_packs_epi32(C, D);
+}
+
+static void ConvertARGBToUV_SSE41(const uint32_t* argb,
+ uint8_t* u, uint8_t* v,
+ int src_width, int do_store) {
+ const int max_width = src_width & ~31;
+ int i;
+ for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
+ __m128i rgb[6], U0, V0, U1, V1;
+ RGB32PackedToPlanar_SSE41(&argb[i], rgb);
+ HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]);
+ HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]);
+ HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]);
+ ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
+
+ RGB32PackedToPlanar_SSE41(&argb[i + 16], rgb);
+ HorizontalAddPack_SSE41(&rgb[0], &rgb[1], &rgb[0]);
+ HorizontalAddPack_SSE41(&rgb[2], &rgb[3], &rgb[2]);
+ HorizontalAddPack_SSE41(&rgb[4], &rgb[5], &rgb[4]);
+ ConvertRGBToUV_SSE41(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
+
+ U0 = _mm_packus_epi16(U0, U1);
+ V0 = _mm_packus_epi16(V0, V1);
+ if (!do_store) {
+ const __m128i prev_u = LOAD_16(u);
+ const __m128i prev_v = LOAD_16(v);
+ U0 = _mm_avg_epu8(U0, prev_u);
+ V0 = _mm_avg_epu8(V0, prev_v);
+ }
+ STORE_16(U0, u);
+ STORE_16(V0, v);
+ }
+ if (i < src_width) { // left-over
+ WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store);
+ }
+}
+
+// Convert 16 packed ARGB 16b-values to r[], g[], b[]
+static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE41(
+ const uint16_t* const rgbx,
+ __m128i* const r, __m128i* const g, __m128i* const b) {
+ const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x
+ const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x
+ const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ...
+ const __m128i in3 = LOAD_16(rgbx + 24); // r6 | ...
+ // aarrggbb as 16-bit.
+ const __m128i shuff0 =
+ _mm_set_epi8(-1, -1, -1, -1, 13, 12, 5, 4, 11, 10, 3, 2, 9, 8, 1, 0);
+ const __m128i shuff1 =
+ _mm_set_epi8(13, 12, 5, 4, -1, -1, -1, -1, 11, 10, 3, 2, 9, 8, 1, 0);
+ const __m128i A0 = _mm_shuffle_epi8(in0, shuff0);
+ const __m128i A1 = _mm_shuffle_epi8(in1, shuff1);
+ const __m128i A2 = _mm_shuffle_epi8(in2, shuff0);
+ const __m128i A3 = _mm_shuffle_epi8(in3, shuff1);
+ // R0R1G0G1
+ // B0B1****
+ // R2R3G2G3
+ // B2B3****
+ // (OR is used to free port 5 for the unpack)
+ const __m128i B0 = _mm_unpacklo_epi32(A0, A1);
+ const __m128i B1 = _mm_or_si128(A0, A1);
+ const __m128i B2 = _mm_unpacklo_epi32(A2, A3);
+ const __m128i B3 = _mm_or_si128(A2, A3);
+ // Gather the channels.
+ *r = _mm_unpacklo_epi64(B0, B2);
+ *g = _mm_unpackhi_epi64(B0, B2);
+ *b = _mm_unpackhi_epi64(B1, B3);
+}
+
+static void ConvertRGBA32ToUV_SSE41(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width) {
+ const int max_width = width & ~15;
+ const uint16_t* const last_rgb = rgb + 4 * max_width;
+ while (rgb < last_rgb) {
+ __m128i r, g, b, U0, V0, U1, V1;
+ RGBA32PackedToPlanar_16b_SSE41(rgb + 0, &r, &g, &b);
+ ConvertRGBToUV_SSE41(&r, &g, &b, &U0, &V0);
+ RGBA32PackedToPlanar_16b_SSE41(rgb + 32, &r, &g, &b);
+ ConvertRGBToUV_SSE41(&r, &g, &b, &U1, &V1);
+ STORE_16(_mm_packus_epi16(U0, U1), u);
+ STORE_16(_mm_packus_epi16(V0, V1), v);
+ u += 16;
+ v += 16;
+ rgb += 2 * 32;
+ }
+ if (max_width < width) { // left-over
+ WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+extern void WebPInitConvertARGBToYUVSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE41(void) {
+ WebPConvertARGBToY = ConvertARGBToY_SSE41;
+ WebPConvertARGBToUV = ConvertARGBToUV_SSE41;
+
+ WebPConvertRGB24ToY = ConvertRGB24ToY_SSE41;
+ WebPConvertBGR24ToY = ConvertBGR24ToY_SSE41;
+
+ WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE41;
+}
+
+//------------------------------------------------------------------------------
+
+#else // !WEBP_USE_SSE41
+
+WEBP_DSP_INIT_STUB(WebPInitSamplersSSE41)
+WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE41)
+
+#endif // WEBP_USE_SSE41
diff --git a/media/libwebp/enc/backward_references_enc.h b/media/libwebp/enc/backward_references_enc.h
index 3a19aa763..539e991cf 100644
--- a/media/libwebp/enc/backward_references_enc.h
+++ b/media/libwebp/enc/backward_references_enc.h
@@ -10,8 +10,8 @@
// Author: Jyrki Alakuijala (jyrki@google.com)
//
-#ifndef WEBP_ENC_BACKWARD_REFERENCES_H_
-#define WEBP_ENC_BACKWARD_REFERENCES_H_
+#ifndef WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
+#define WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
#include <assert.h>
#include <stdlib.h>
@@ -91,11 +91,6 @@ static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) {
return p->len;
}
-static WEBP_INLINE uint32_t PixOrCopyArgb(const PixOrCopy* const p) {
- assert(p->mode == kLiteral);
- return p->argb_or_distance;
-}
-
static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
assert(p->mode == kCacheIdx);
assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
@@ -113,6 +108,16 @@ static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
#define HASH_BITS 18
#define HASH_SIZE (1 << HASH_BITS)
+// If you change this, you need MAX_LENGTH_BITS + WINDOW_SIZE_BITS <= 32 as it
+// is used in VP8LHashChain.
+#define MAX_LENGTH_BITS 12
+#define WINDOW_SIZE_BITS 20
+// We want the max value to be attainable and stored in MAX_LENGTH_BITS bits.
+#define MAX_LENGTH ((1 << MAX_LENGTH_BITS) - 1)
+#if MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32
+#error "MAX_LENGTH_BITS + WINDOW_SIZE_BITS > 32"
+#endif
+
typedef struct VP8LHashChain VP8LHashChain;
struct VP8LHashChain {
// The 20 most significant bits contain the offset at which the best match
@@ -134,6 +139,24 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
int low_effort);
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
+static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p,
+ const int base_position) {
+ return p->offset_length_[base_position] >> MAX_LENGTH_BITS;
+}
+
+static WEBP_INLINE int VP8LHashChainFindLength(const VP8LHashChain* const p,
+ const int base_position) {
+ return p->offset_length_[base_position] & ((1U << MAX_LENGTH_BITS) - 1);
+}
+
+static WEBP_INLINE void VP8LHashChainFindCopy(const VP8LHashChain* const p,
+ int base_position,
+ int* const offset_ptr,
+ int* const length_ptr) {
+ *offset_ptr = VP8LHashChainFindOffset(p, base_position);
+ *length_ptr = VP8LHashChainFindLength(p, base_position);
+}
+
// -----------------------------------------------------------------------------
// VP8LBackwardRefs (block-based backward-references storage)
@@ -158,9 +181,6 @@ struct VP8LBackwardRefs {
void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size);
// Release memory for backward references.
void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs);
-// Copies the 'src' backward refs to the 'dst'. Returns 0 in case of error.
-int VP8LBackwardRefsCopy(const VP8LBackwardRefs* const src,
- VP8LBackwardRefs* const dst);
// Cursor for iterating on references content
typedef struct {
@@ -189,6 +209,12 @@ static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) {
// -----------------------------------------------------------------------------
// Main entry points
+enum VP8LLZ77Type {
+ kLZ77Standard = 1,
+ kLZ77RLE = 2,
+ kLZ77Box = 4
+};
+
// Evaluates best possible backward references for specified quality.
// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache
// bits to use (passing 0 implies disabling the local color cache).
@@ -197,11 +223,12 @@ static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) {
// refs[0] or refs[1].
VP8LBackwardRefs* VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
- int low_effort, int* const cache_bits,
- const VP8LHashChain* const hash_chain, VP8LBackwardRefs refs[2]);
+ int low_effort, int lz77_types_to_try, int* const cache_bits,
+ const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_tmp1,
+ VP8LBackwardRefs* const refs_tmp2);
#ifdef __cplusplus
}
#endif
-#endif // WEBP_ENC_BACKWARD_REFERENCES_H_
+#endif // WEBP_ENC_BACKWARD_REFERENCES_ENC_H_
diff --git a/media/libwebp/enc/cost_enc.h b/media/libwebp/enc/cost_enc.h
index 99e4b37aa..d731ee2fa 100644
--- a/media/libwebp/enc/cost_enc.h
+++ b/media/libwebp/enc/cost_enc.h
@@ -11,12 +11,12 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_ENC_COST_H_
-#define WEBP_ENC_COST_H_
+#ifndef WEBP_ENC_COST_ENC_H_
+#define WEBP_ENC_COST_ENC_H_
#include <assert.h>
#include <stdlib.h>
-#include "./vp8i_enc.h"
+#include "../enc/vp8i_enc.h"
#ifdef __cplusplus
extern "C" {
@@ -79,4 +79,4 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
} // extern "C"
#endif
-#endif /* WEBP_ENC_COST_H_ */
+#endif /* WEBP_ENC_COST_ENC_H_ */
diff --git a/media/libwebp/enc/histogram_enc.h b/media/libwebp/enc/histogram_enc.h
index a9d258a16..4fbb73702 100644
--- a/media/libwebp/enc/histogram_enc.h
+++ b/media/libwebp/enc/histogram_enc.h
@@ -11,12 +11,12 @@
//
// Models the histograms of literal and distance codes.
-#ifndef WEBP_ENC_HISTOGRAM_H_
-#define WEBP_ENC_HISTOGRAM_H_
+#ifndef WEBP_ENC_HISTOGRAM_ENC_H_
+#define WEBP_ENC_HISTOGRAM_ENC_H_
#include <string.h>
-#include "./backward_references_enc.h"
+#include "../enc/backward_references_enc.h"
#include "../webp/format_constants.h"
#include "../webp/types.h"
@@ -90,7 +90,9 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits);
// Accumulate a token 'v' into a histogram.
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
- const PixOrCopy* const v);
+ const PixOrCopy* const v,
+ int (*const distance_modifier)(int, int),
+ int distance_modifier_arg0);
static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
return NUM_LITERAL_CODES + NUM_LENGTH_CODES +
@@ -103,14 +105,11 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
int quality, int low_effort,
int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_in,
- VP8LHistogramSet* const tmp_histos,
+ VP8LHistogram* const tmp_histo,
uint16_t* const histogram_symbols);
// Returns the entropy for the symbols in the input array.
-// Also sets trivial_symbol to the code value, if the array has only one code
-// value. Otherwise, set it to VP8L_NON_TRIVIAL_SYM.
-double VP8LBitsEntropy(const uint32_t* const array, int n,
- uint32_t* const trivial_symbol);
+double VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
@@ -120,4 +119,4 @@ double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
}
#endif
-#endif // WEBP_ENC_HISTOGRAM_H_
+#endif // WEBP_ENC_HISTOGRAM_ENC_H_
diff --git a/media/libwebp/enc/vp8i_enc.h b/media/libwebp/enc/vp8i_enc.h
index 93c95ecbf..8972d9f10 100644
--- a/media/libwebp/enc/vp8i_enc.h
+++ b/media/libwebp/enc/vp8i_enc.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_ENC_VP8ENCI_H_
-#define WEBP_ENC_VP8ENCI_H_
+#ifndef WEBP_ENC_VP8I_ENC_H_
+#define WEBP_ENC_VP8I_ENC_H_
#include <string.h> // for memcpy()
#include "../dec/common_dec.h"
@@ -30,8 +30,8 @@ extern "C" {
// Various defines and enums
// version numbers
-#define ENC_MAJ_VERSION 0
-#define ENC_MIN_VERSION 6
+#define ENC_MAJ_VERSION 1
+#define ENC_MIN_VERSION 0
#define ENC_REV_VERSION 0
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
@@ -75,10 +75,10 @@ typedef enum { // Rate-distortion optimization levels
#define U_OFF_ENC (16)
#define V_OFF_ENC (16 + 8)
-extern const int VP8Scan[16]; // in quant.c
-extern const int VP8UVModeOffsets[4]; // in analyze.c
-extern const int VP8I16ModeOffsets[4];
-extern const int VP8I4ModeOffsets[NUM_BMODES];
+extern const uint16_t VP8Scan[16];
+extern const uint16_t VP8UVModeOffsets[4];
+extern const uint16_t VP8I16ModeOffsets[4];
+extern const uint16_t VP8I4ModeOffsets[NUM_BMODES];
// Layout of prediction blocks
// intra 16x16
@@ -120,6 +120,9 @@ static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) {
// Uncomment the following to remove token-buffer code:
// #define DISABLE_TOKEN_BUFFER
+// quality below which error-diffusion is enabled
+#define ERROR_DIFFUSION_QUALITY 98
+
//------------------------------------------------------------------------------
// Headers
@@ -201,6 +204,8 @@ typedef struct {
score_t i4_penalty_; // penalty for using Intra4
} VP8SegmentInfo;
+typedef int8_t DError[2 /* u/v */][2 /* top or left */];
+
// Handy transient struct to accumulate score and info during RD-optimization
// and mode evaluation.
typedef struct {
@@ -213,6 +218,7 @@ typedef struct {
uint8_t modes_i4[16]; // mode numbers for intra4 predictions
int mode_uv; // mode number of chroma prediction
uint32_t nz; // non-zero blocks
+ int8_t derr[2][3]; // DC diffusion errors for U/V for blocks #1/2/3
} VP8ModeScore;
// Iterator structure to iterate through macroblocks, pointing to the
@@ -242,6 +248,9 @@ typedef struct {
int count_down0_; // starting counter value (for progress)
int percent0_; // saved initial progress percent
+ DError left_derr_; // left error diffusion (u/v)
+ DError *top_derr_; // top diffusion error - NULL if disabled
+
uint8_t* y_left_; // left luma samples (addressable from index -1 to 15).
uint8_t* u_left_; // left u samples (addressable from index -1 to 7)
uint8_t* v_left_; // left v samples (addressable from index -1 to 7)
@@ -330,9 +339,6 @@ int VP8RecordCoeffTokens(int ctx, const struct VP8Residual* const res,
// Estimate the final coded size given a set of 'probas'.
size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas);
-// unused for now
-void VP8TokenToStats(const VP8TBuffer* const b, proba_t* const stats);
-
#endif // !DISABLE_TOKEN_BUFFER
//------------------------------------------------------------------------------
@@ -404,6 +410,7 @@ struct VP8Encoder {
uint8_t* uv_top_; // top u/v samples.
// U and V are packed into 16 bytes (8 U + 8 V)
LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off)
+ DError* top_derr_; // diffusion error (NULL if disabled)
};
//------------------------------------------------------------------------------
@@ -502,19 +509,10 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
// compressibility (no guarantee, though). Assumes that pic->use_argb is true.
void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
- // in near_lossless.c
-// Near lossless preprocessing in RGB color-space.
-int VP8ApplyNearLossless(int xsize, int ysize, uint32_t* argb, int quality);
-// Near lossless adjustment for predictors.
-void VP8ApplyNearLosslessPredict(int xsize, int ysize, int pred_bits,
- const uint32_t* argb_orig,
- uint32_t* argb, uint32_t* argb_scratch,
- const uint32_t* const transform_data,
- int quality, int subtract_green);
//------------------------------------------------------------------------------
#ifdef __cplusplus
} // extern "C"
#endif
-#endif /* WEBP_ENC_VP8ENCI_H_ */
+#endif /* WEBP_ENC_VP8I_ENC_H_ */
diff --git a/media/libwebp/enc/vp8li_enc.h b/media/libwebp/enc/vp8li_enc.h
index 8c5fbcbb2..5dcba9ef0 100644
--- a/media/libwebp/enc/vp8li_enc.h
+++ b/media/libwebp/enc/vp8li_enc.h
@@ -11,11 +11,20 @@
//
// Author: Vikas Arora (vikaas.arora@gmail.com)
-#ifndef WEBP_ENC_VP8LI_H_
-#define WEBP_ENC_VP8LI_H_
+#ifndef WEBP_ENC_VP8LI_ENC_H_
+#define WEBP_ENC_VP8LI_ENC_H_
-#include "./backward_references_enc.h"
-#include "./histogram_enc.h"
+#ifdef HAVE_CONFIG_H
+#include "../webp/config.h"
+#endif
+// Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to
+// disable near-lossless, or it is enabled by default.
+#ifndef WEBP_NEAR_LOSSLESS
+#define WEBP_NEAR_LOSSLESS 1
+#endif
+
+#include "../enc/backward_references_enc.h"
+#include "../enc/histogram_enc.h"
#include "../utils/bit_writer_utils.h"
#include "../webp/encode.h"
#include "../webp/format_constants.h"
@@ -27,16 +36,24 @@ extern "C" {
// maximum value of transform_bits_ in VP8LEncoder.
#define MAX_TRANSFORM_BITS 6
+typedef enum {
+ kEncoderNone = 0,
+ kEncoderARGB,
+ kEncoderNearLossless,
+ kEncoderPalette
+} VP8LEncoderARGBContent;
+
typedef struct {
const WebPConfig* config_; // user configuration and parameters
const WebPPicture* pic_; // input picture.
- uint32_t* argb_; // Transformed argb image data.
- uint32_t* argb_scratch_; // Scratch memory for argb rows
- // (used for prediction).
- uint32_t* transform_data_; // Scratch memory for transform data.
- uint32_t* transform_mem_; // Currently allocated memory.
- size_t transform_mem_size_; // Currently allocated memory size.
+ uint32_t* argb_; // Transformed argb image data.
+ VP8LEncoderARGBContent argb_content_; // Content type of the argb buffer.
+ uint32_t* argb_scratch_; // Scratch memory for argb rows
+ // (used for prediction).
+ uint32_t* transform_data_; // Scratch memory for transform data.
+ uint32_t* transform_mem_; // Currently allocated memory.
+ size_t transform_mem_size_; // Currently allocated memory size.
int current_width_; // Corresponds to packed image width.
@@ -54,8 +71,7 @@ typedef struct {
uint32_t palette_[MAX_PALETTE_SIZE];
// Some 'scratch' (potentially large) objects.
- struct VP8LBackwardRefs refs_[2]; // Backward Refs array corresponding to
- // LZ77 & RLE coding.
+ struct VP8LBackwardRefs refs_[3]; // Backward Refs array for temporaries.
VP8LHashChain hash_chain_; // HashChain data for constructing
// backward references.
} VP8LEncoder;
@@ -75,6 +91,13 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
const WebPPicture* const picture,
VP8LBitWriter* const bw, int use_cache);
+#if (WEBP_NEAR_LOSSLESS == 1)
+// in near_lossless.c
+// Near lossless preprocessing in RGB color-space.
+int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
+ uint32_t* const argb_dst);
+#endif
+
//------------------------------------------------------------------------------
// Image transforms in predictor.c.
@@ -92,4 +115,4 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
} // extern "C"
#endif
-#endif /* WEBP_ENC_VP8LI_H_ */
+#endif /* WEBP_ENC_VP8LI_ENC_H_ */
diff --git a/media/libwebp/update.sh b/media/libwebp/update.sh
index 57cd45996..652993004 100644
--- a/media/libwebp/update.sh
+++ b/media/libwebp/update.sh
@@ -56,8 +56,10 @@ cp $1/src/dsp/rescaler_sse2.c dsp
cp $1/src/dsp/upsampling.c dsp
cp $1/src/dsp/upsampling_neon.c dsp
cp $1/src/dsp/upsampling_sse2.c dsp
+cp $1/src/dsp/upsampling_sse41.c dsp
cp $1/src/dsp/yuv.c dsp
cp $1/src/dsp/yuv_sse2.c dsp
+cp $1/src/dsp/yuv_sse41.c dsp
mkdir -p enc
cp $1/src/enc/*.h enc
@@ -74,3 +76,5 @@ cp $1/src/utils/random_utils.c utils
cp $1/src/utils/rescaler_utils.c utils
cp $1/src/utils/thread_utils.c utils
cp $1/src/utils/utils.c utils
+
+find . \( -name "*.c" -o -name "*.h" \) -exec sed -i 's/#include "src\//#include "..\//g' {} \;
diff --git a/media/libwebp/utils/bit_reader_inl_utils.h b/media/libwebp/utils/bit_reader_inl_utils.h
index fd7fb0446..2bb9a1918 100644
--- a/media/libwebp/utils/bit_reader_inl_utils.h
+++ b/media/libwebp/utils/bit_reader_inl_utils.h
@@ -13,8 +13,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_UTILS_BIT_READER_INL_H_
-#define WEBP_UTILS_BIT_READER_INL_H_
+#ifndef WEBP_UTILS_BIT_READER_INL_UTILS_H_
+#define WEBP_UTILS_BIT_READER_INL_UTILS_H_
#ifdef HAVE_CONFIG_H
#include "../webp/config.h"
@@ -23,9 +23,9 @@
#include <string.h> // for memcpy
#include "../dsp/dsp.h"
-#include "./bit_reader_utils.h"
-#include "./endian_inl_utils.h"
-#include "./utils.h"
+#include "../utils/bit_reader_utils.h"
+#include "../utils/endian_inl_utils.h"
+#include "../utils/utils.h"
#ifdef __cplusplus
extern "C" {
@@ -187,4 +187,4 @@ static WEBP_INLINE int VP8GetBitAlt(VP8BitReader* const br, int prob) {
} // extern "C"
#endif
-#endif // WEBP_UTILS_BIT_READER_INL_H_
+#endif // WEBP_UTILS_BIT_READER_INL_UTILS_H_
diff --git a/media/libwebp/utils/bit_reader_utils.c b/media/libwebp/utils/bit_reader_utils.c
index c3157e8fe..a7cb193bd 100644
--- a/media/libwebp/utils/bit_reader_utils.c
+++ b/media/libwebp/utils/bit_reader_utils.c
@@ -15,7 +15,7 @@
#include "../webp/config.h"
#endif
-#include "./bit_reader_inl_utils.h"
+#include "../utils/bit_reader_inl_utils.h"
#include "../utils/utils.h"
//------------------------------------------------------------------------------
diff --git a/media/libwebp/utils/bit_reader_utils.h b/media/libwebp/utils/bit_reader_utils.h
index ec3426cd1..53e9db6ad 100644
--- a/media/libwebp/utils/bit_reader_utils.h
+++ b/media/libwebp/utils/bit_reader_utils.h
@@ -12,8 +12,8 @@
// Author: Skal (pascal.massimino@gmail.com)
// Vikas Arora (vikaas.arora@gmail.com)
-#ifndef WEBP_UTILS_BIT_READER_H_
-#define WEBP_UTILS_BIT_READER_H_
+#ifndef WEBP_UTILS_BIT_READER_UTILS_H_
+#define WEBP_UTILS_BIT_READER_UTILS_H_
#include <assert.h>
#ifdef _MSC_VER
@@ -155,9 +155,10 @@ static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) {
// For jumping over a number of bits in the bit stream when accessed with
// VP8LPrefetchBits and VP8LFillBitWindow.
+// This function does *not* set br->eos_, since it's speed-critical.
+// Use with extreme care!
static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) {
br->bit_pos_ = val;
- br->eos_ = VP8LIsEndOfStream(br);
}
// Advances the read buffer by 4 bytes to make room for reading next 32 bits.
@@ -171,4 +172,4 @@ static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_BIT_READER_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 9c02bbc06..9e9c2b729 100644
--- a/media/libwebp/utils/bit_writer_utils.h
+++ b/media/libwebp/utils/bit_writer_utils.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_UTILS_BIT_WRITER_H_
-#define WEBP_UTILS_BIT_WRITER_H_
+#ifndef WEBP_UTILS_BIT_WRITER_UTILS_H_
+#define WEBP_UTILS_BIT_WRITER_UTILS_H_
#include "../webp/types.h"
@@ -100,16 +100,24 @@ typedef struct {
int error_;
} VP8LBitWriter;
-static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) {
+static WEBP_INLINE size_t VP8LBitWriterNumBytes(const VP8LBitWriter* const bw) {
return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3);
}
// Returns false in case of memory allocation error.
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
+// Returns false in case of memory allocation error.
+int VP8LBitWriterClone(const VP8LBitWriter* const src,
+ VP8LBitWriter* const dst);
// Finalize the bitstream coding. Returns a pointer to the internal buffer.
uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw);
// Release any pending memory and zeroes the object.
void VP8LBitWriterWipeOut(VP8LBitWriter* const bw);
+// Resets the cursor of the BitWriter bw to when it was like in bw_init.
+void VP8LBitWriterReset(const VP8LBitWriter* const bw_init,
+ VP8LBitWriter* const bw);
+// Swaps the memory held by two BitWriters.
+void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst);
// Internal function for VP8LPutBits flushing 32 bits from the written state.
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw);
@@ -143,4 +151,4 @@ static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_BIT_WRITER_H_ */
+#endif /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */
diff --git a/media/libwebp/utils/color_cache_utils.c b/media/libwebp/utils/color_cache_utils.c
index 0172590c4..c5eb0d8a9 100644
--- a/media/libwebp/utils/color_cache_utils.c
+++ b/media/libwebp/utils/color_cache_utils.c
@@ -14,8 +14,8 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "./color_cache_utils.h"
-#include "./utils.h"
+#include "../utils/color_cache_utils.h"
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// VP8LColorCache.
diff --git a/media/libwebp/utils/color_cache_utils.h b/media/libwebp/utils/color_cache_utils.h
index c373e6b36..c46131277 100644
--- a/media/libwebp/utils/color_cache_utils.h
+++ b/media/libwebp/utils/color_cache_utils.h
@@ -12,8 +12,10 @@
// Authors: Jyrki Alakuijala (jyrki@google.com)
// Urvang Joshi (urvang@google.com)
-#ifndef WEBP_UTILS_COLOR_CACHE_H_
-#define WEBP_UTILS_COLOR_CACHE_H_
+#ifndef WEBP_UTILS_COLOR_CACHE_UTILS_H_
+#define WEBP_UTILS_COLOR_CACHE_UTILS_H_
+
+#include <assert.h>
#include "../webp/types.h"
@@ -30,7 +32,7 @@ typedef struct {
static const uint64_t kHashMul = 0x1e35a7bdull;
-static WEBP_INLINE int HashPix(uint32_t argb, int shift) {
+static WEBP_INLINE int VP8LHashPix(uint32_t argb, int shift) {
return (int)(((argb * kHashMul) & 0xffffffffu) >> shift);
}
@@ -48,19 +50,19 @@ static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc,
static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc,
uint32_t argb) {
- const int key = HashPix(argb, cc->hash_shift_);
+ const int key = VP8LHashPix(argb, cc->hash_shift_);
cc->colors_[key] = argb;
}
static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc,
uint32_t argb) {
- return HashPix(argb, cc->hash_shift_);
+ return VP8LHashPix(argb, cc->hash_shift_);
}
// Return the key if cc contains argb, and -1 otherwise.
static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
uint32_t argb) {
- const int key = HashPix(argb, cc->hash_shift_);
+ const int key = VP8LHashPix(argb, cc->hash_shift_);
return (cc->colors_[key] == argb) ? key : -1;
}
@@ -82,4 +84,4 @@ void VP8LColorCacheClear(VP8LColorCache* const color_cache);
}
#endif
-#endif // WEBP_UTILS_COLOR_CACHE_H_
+#endif // WEBP_UTILS_COLOR_CACHE_UTILS_H_
diff --git a/media/libwebp/utils/endian_inl_utils.h b/media/libwebp/utils/endian_inl_utils.h
index e11260ff7..1c01450b9 100644
--- a/media/libwebp/utils/endian_inl_utils.h
+++ b/media/libwebp/utils/endian_inl_utils.h
@@ -9,8 +9,8 @@
//
// Endian related functions.
-#ifndef WEBP_UTILS_ENDIAN_INL_H_
-#define WEBP_UTILS_ENDIAN_INL_H_
+#ifndef WEBP_UTILS_ENDIAN_INL_UTILS_H_
+#define WEBP_UTILS_ENDIAN_INL_UTILS_H_
#ifdef HAVE_CONFIG_H
#include "../webp/config.h"
@@ -19,13 +19,6 @@
#include "../dsp/dsp.h"
#include "../webp/types.h"
-// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
-#if !defined(WORDS_BIGENDIAN) && \
- (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
- (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
-#define WORDS_BIGENDIAN
-#endif
-
#if defined(WORDS_BIGENDIAN)
#define HToLE32 BSwap32
#define HToLE16 BSwap16
@@ -97,4 +90,4 @@ static WEBP_INLINE uint64_t BSwap64(uint64_t x) {
#endif // HAVE_BUILTIN_BSWAP64
}
-#endif // WEBP_UTILS_ENDIAN_INL_H_
+#endif // WEBP_UTILS_ENDIAN_INL_UTILS_H_
diff --git a/media/libwebp/utils/filters_utils.c b/media/libwebp/utils/filters_utils.c
index 49c1d18a2..b9c99b130 100644
--- a/media/libwebp/utils/filters_utils.c
+++ b/media/libwebp/utils/filters_utils.c
@@ -11,7 +11,7 @@
//
// Author: Urvang (urvang@google.com)
-#include "./filters_utils.h"
+#include "../utils/filters_utils.h"
#include <stdlib.h>
#include <string.h>
diff --git a/media/libwebp/utils/filters_utils.h b/media/libwebp/utils/filters_utils.h
index 088b132fc..9466030e5 100644
--- a/media/libwebp/utils/filters_utils.h
+++ b/media/libwebp/utils/filters_utils.h
@@ -11,8 +11,8 @@
//
// Author: Urvang (urvang@google.com)
-#ifndef WEBP_UTILS_FILTERS_H_
-#define WEBP_UTILS_FILTERS_H_
+#ifndef WEBP_UTILS_FILTERS_UTILS_H_
+#define WEBP_UTILS_FILTERS_UTILS_H_
#include "../webp/types.h"
#include "../dsp/dsp.h"
@@ -29,4 +29,4 @@ WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
} // extern "C"
#endif
-#endif /* WEBP_UTILS_FILTERS_H_ */
+#endif /* WEBP_UTILS_FILTERS_UTILS_H_ */
diff --git a/media/libwebp/utils/huffman_encode_utils.h b/media/libwebp/utils/huffman_encode_utils.h
index a15716514..236f266e4 100644
--- a/media/libwebp/utils/huffman_encode_utils.h
+++ b/media/libwebp/utils/huffman_encode_utils.h
@@ -11,8 +11,8 @@
//
// Entropy encoding (Huffman) for webp lossless
-#ifndef WEBP_UTILS_HUFFMAN_ENCODE_H_
-#define WEBP_UTILS_HUFFMAN_ENCODE_H_
+#ifndef WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
+#define WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
#include "../webp/types.h"
@@ -57,4 +57,4 @@ void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
}
#endif
-#endif // WEBP_UTILS_HUFFMAN_ENCODE_H_
+#endif // WEBP_UTILS_HUFFMAN_ENCODE_UTILS_H_
diff --git a/media/libwebp/utils/huffman_utils.c b/media/libwebp/utils/huffman_utils.c
index 008b5d746..a2b4b3f89 100644
--- a/media/libwebp/utils/huffman_utils.c
+++ b/media/libwebp/utils/huffman_utils.c
@@ -14,8 +14,8 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "./huffman_utils.h"
-#include "./utils.h"
+#include "../utils/huffman_utils.h"
+#include "../utils/utils.h"
#include "../webp/format_constants.h"
// Huffman data read via DecodeImageStream is represented in two (red and green)
diff --git a/media/libwebp/utils/huffman_utils.h b/media/libwebp/utils/huffman_utils.h
index c6dd6aaa4..7f241aab9 100644
--- a/media/libwebp/utils/huffman_utils.h
+++ b/media/libwebp/utils/huffman_utils.h
@@ -11,8 +11,8 @@
//
// Author: Urvang Joshi (urvang@google.com)
-#ifndef WEBP_UTILS_HUFFMAN_H_
-#define WEBP_UTILS_HUFFMAN_H_
+#ifndef WEBP_UTILS_HUFFMAN_UTILS_H_
+#define WEBP_UTILS_HUFFMAN_UTILS_H_
#include <assert.h>
#include "../webp/format_constants.h"
@@ -85,4 +85,4 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
} // extern "C"
#endif
-#endif // WEBP_UTILS_HUFFMAN_H_
+#endif // WEBP_UTILS_HUFFMAN_UTILS_H_
diff --git a/media/libwebp/utils/quant_levels_dec_utils.c b/media/libwebp/utils/quant_levels_dec_utils.c
index d4d23d314..5c498382d 100644
--- a/media/libwebp/utils/quant_levels_dec_utils.c
+++ b/media/libwebp/utils/quant_levels_dec_utils.c
@@ -14,11 +14,11 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./quant_levels_dec_utils.h"
+#include "../utils/quant_levels_dec_utils.h"
#include <string.h> // for memset
-#include "./utils.h"
+#include "../utils/utils.h"
// #define USE_DITHERING // uncomment to enable ordered dithering (not vital)
@@ -71,10 +71,11 @@ typedef struct {
//------------------------------------------------------------------------------
-#define CLIP_MASK (int)(~0U << (8 + DFIX))
+#define CLIP_8b_MASK (int)(~0U << (8 + DFIX))
static WEBP_INLINE uint8_t clip_8b(int v) {
- return (!(v & CLIP_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u;
+ return (!(v & CLIP_8b_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u;
}
+#undef CLIP_8b_MASK
// vertical accumulation
static void VFilter(SmoothParams* const p) {
diff --git a/media/libwebp/utils/quant_levels_dec_utils.h b/media/libwebp/utils/quant_levels_dec_utils.h
index 59a13495d..4a59e06fe 100644
--- a/media/libwebp/utils/quant_levels_dec_utils.h
+++ b/media/libwebp/utils/quant_levels_dec_utils.h
@@ -11,8 +11,8 @@
//
// Author: Vikas Arora (vikasa@google.com)
-#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_H_
-#define WEBP_UTILS_QUANT_LEVELS_DEC_H_
+#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
+#define WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
#include "../webp/types.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_H_ */
+#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */
diff --git a/media/libwebp/utils/quant_levels_utils.c b/media/libwebp/utils/quant_levels_utils.c
index 73174e8ab..275781927 100644
--- a/media/libwebp/utils/quant_levels_utils.c
+++ b/media/libwebp/utils/quant_levels_utils.c
@@ -14,7 +14,7 @@
#include <assert.h>
-#include "./quant_levels_utils.h"
+#include "../utils/quant_levels_utils.h"
#define NUM_SYMBOLS 256
diff --git a/media/libwebp/utils/quant_levels_utils.h b/media/libwebp/utils/quant_levels_utils.h
index 1cb5a32ca..837bd2730 100644
--- a/media/libwebp/utils/quant_levels_utils.h
+++ b/media/libwebp/utils/quant_levels_utils.h
@@ -11,8 +11,8 @@
//
// Author: Vikas Arora (vikasa@google.com)
-#ifndef WEBP_UTILS_QUANT_LEVELS_H_
-#define WEBP_UTILS_QUANT_LEVELS_H_
+#ifndef WEBP_UTILS_QUANT_LEVELS_UTILS_H_
+#define WEBP_UTILS_QUANT_LEVELS_UTILS_H_
#include <stdlib.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_H_ */
+#endif /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */
diff --git a/media/libwebp/utils/random_utils.c b/media/libwebp/utils/random_utils.c
index 9f1e4154a..f2dd45a03 100644
--- a/media/libwebp/utils/random_utils.c
+++ b/media/libwebp/utils/random_utils.c
@@ -12,7 +12,7 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <string.h>
-#include "./random_utils.h"
+#include "../utils/random_utils.h"
//------------------------------------------------------------------------------
diff --git a/media/libwebp/utils/random_utils.h b/media/libwebp/utils/random_utils.h
index c392a615c..7b58de8c9 100644
--- a/media/libwebp/utils/random_utils.h
+++ b/media/libwebp/utils/random_utils.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_UTILS_RANDOM_H_
-#define WEBP_UTILS_RANDOM_H_
+#ifndef WEBP_UTILS_RANDOM_UTILS_H_
+#define WEBP_UTILS_RANDOM_UTILS_H_
#include <assert.h>
#include "../webp/types.h"
@@ -60,4 +60,4 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_RANDOM_H_ */
+#endif /* WEBP_UTILS_RANDOM_UTILS_H_ */
diff --git a/media/libwebp/utils/rescaler_utils.c b/media/libwebp/utils/rescaler_utils.c
index 0d1f80da2..6e384f507 100644
--- a/media/libwebp/utils/rescaler_utils.c
+++ b/media/libwebp/utils/rescaler_utils.c
@@ -15,7 +15,7 @@
#include <stdlib.h>
#include <string.h>
#include "../dsp/dsp.h"
-#include "./rescaler_utils.h"
+#include "../utils/rescaler_utils.h"
//------------------------------------------------------------------------------
@@ -85,11 +85,13 @@ int WebPRescalerGetScaledDimensions(int src_width, int src_height,
// if width is unspecified, scale original proportionally to height ratio.
if (width == 0) {
- width = (src_width * height + src_height / 2) / src_height;
+ width =
+ (int)(((uint64_t)src_width * height + src_height / 2) / src_height);
}
// if height is unspecified, scale original proportionally to width ratio.
if (height == 0) {
- height = (src_height * width + src_width / 2) / src_width;
+ height =
+ (int)(((uint64_t)src_height * width + src_width / 2) / src_width);
}
// Check if the overall dimensions still make sense.
if (width <= 0 || height <= 0) {
diff --git a/media/libwebp/utils/rescaler_utils.h b/media/libwebp/utils/rescaler_utils.h
index 98b01a76d..1c7b31d7f 100644
--- a/media/libwebp/utils/rescaler_utils.h
+++ b/media/libwebp/utils/rescaler_utils.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_UTILS_RESCALER_H_
-#define WEBP_UTILS_RESCALER_H_
+#ifndef WEBP_UTILS_RESCALER_UTILS_H_
+#define WEBP_UTILS_RESCALER_UTILS_H_
#ifdef __cplusplus
extern "C" {
@@ -98,4 +98,4 @@ int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
} // extern "C"
#endif
-#endif /* WEBP_UTILS_RESCALER_H_ */
+#endif /* WEBP_UTILS_RESCALER_UTILS_H_ */
diff --git a/media/libwebp/utils/thread_utils.c b/media/libwebp/utils/thread_utils.c
index 1729060c7..e87ffbeac 100644
--- a/media/libwebp/utils/thread_utils.c
+++ b/media/libwebp/utils/thread_utils.c
@@ -13,8 +13,8 @@
#include <assert.h>
#include <string.h> // for memset()
-#include "./thread_utils.h"
-#include "./utils.h"
+#include "../utils/thread_utils.h"
+#include "../utils/utils.h"
#ifdef WEBP_USE_THREAD
@@ -50,11 +50,11 @@ typedef struct {
#endif // _WIN32
-struct WebPWorkerImpl {
+typedef struct {
pthread_mutex_t mutex_;
pthread_cond_t condition_;
pthread_t thread_;
-};
+} WebPWorkerImpl;
#if defined(_WIN32)
@@ -201,25 +201,24 @@ static int pthread_cond_wait(pthread_cond_t* const condition,
//------------------------------------------------------------------------------
-static void Execute(WebPWorker* const worker); // Forward declaration.
-
static THREADFN ThreadLoop(void* ptr) {
WebPWorker* const worker = (WebPWorker*)ptr;
+ WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_;
int done = 0;
while (!done) {
- pthread_mutex_lock(&worker->impl_->mutex_);
+ pthread_mutex_lock(&impl->mutex_);
while (worker->status_ == OK) { // wait in idling mode
- pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
+ pthread_cond_wait(&impl->condition_, &impl->mutex_);
}
if (worker->status_ == WORK) {
- Execute(worker);
+ WebPGetWorkerInterface()->Execute(worker);
worker->status_ = OK;
} else if (worker->status_ == NOT_OK) { // finish the worker
done = 1;
}
// signal to the main thread that we're done (for Sync())
- pthread_cond_signal(&worker->impl_->condition_);
- pthread_mutex_unlock(&worker->impl_->mutex_);
+ pthread_cond_signal(&impl->condition_);
+ pthread_mutex_unlock(&impl->mutex_);
}
return THREAD_RETURN(NULL); // Thread is finished
}
@@ -229,21 +228,22 @@ static void ChangeState(WebPWorker* const worker, WebPWorkerStatus new_status) {
// No-op when attempting to change state on a thread that didn't come up.
// Checking status_ without acquiring the lock first would result in a data
// race.
- if (worker->impl_ == NULL) return;
+ WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_;
+ if (impl == NULL) return;
- pthread_mutex_lock(&worker->impl_->mutex_);
+ pthread_mutex_lock(&impl->mutex_);
if (worker->status_ >= OK) {
// wait for the worker to finish
while (worker->status_ != OK) {
- pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
+ pthread_cond_wait(&impl->condition_, &impl->mutex_);
}
// assign new status and release the working thread if needed
if (new_status != OK) {
worker->status_ = new_status;
- pthread_cond_signal(&worker->impl_->condition_);
+ pthread_cond_signal(&impl->condition_);
}
}
- pthread_mutex_unlock(&worker->impl_->mutex_);
+ pthread_mutex_unlock(&impl->mutex_);
}
#endif // WEBP_USE_THREAD
@@ -268,26 +268,28 @@ static int Reset(WebPWorker* const worker) {
worker->had_error = 0;
if (worker->status_ < OK) {
#ifdef WEBP_USE_THREAD
- worker->impl_ = (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(*worker->impl_));
+ WebPWorkerImpl* const impl =
+ (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(WebPWorkerImpl));
+ worker->impl_ = (void*)impl;
if (worker->impl_ == NULL) {
return 0;
}
- if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) {
+ if (pthread_mutex_init(&impl->mutex_, NULL)) {
goto Error;
}
- if (pthread_cond_init(&worker->impl_->condition_, NULL)) {
- pthread_mutex_destroy(&worker->impl_->mutex_);
+ if (pthread_cond_init(&impl->condition_, NULL)) {
+ pthread_mutex_destroy(&impl->mutex_);
goto Error;
}
- pthread_mutex_lock(&worker->impl_->mutex_);
- ok = !pthread_create(&worker->impl_->thread_, NULL, ThreadLoop, worker);
+ pthread_mutex_lock(&impl->mutex_);
+ ok = !pthread_create(&impl->thread_, NULL, ThreadLoop, worker);
if (ok) worker->status_ = OK;
- pthread_mutex_unlock(&worker->impl_->mutex_);
+ pthread_mutex_unlock(&impl->mutex_);
if (!ok) {
- pthread_mutex_destroy(&worker->impl_->mutex_);
- pthread_cond_destroy(&worker->impl_->condition_);
+ pthread_mutex_destroy(&impl->mutex_);
+ pthread_cond_destroy(&impl->condition_);
Error:
- WebPSafeFree(worker->impl_);
+ WebPSafeFree(impl);
worker->impl_ = NULL;
return 0;
}
@@ -318,11 +320,12 @@ static void Launch(WebPWorker* const worker) {
static void End(WebPWorker* const worker) {
#ifdef WEBP_USE_THREAD
if (worker->impl_ != NULL) {
+ WebPWorkerImpl* const impl = (WebPWorkerImpl*)worker->impl_;
ChangeState(worker, NOT_OK);
- pthread_join(worker->impl_->thread_, NULL);
- pthread_mutex_destroy(&worker->impl_->mutex_);
- pthread_cond_destroy(&worker->impl_->condition_);
- WebPSafeFree(worker->impl_);
+ pthread_join(impl->thread_, NULL);
+ pthread_mutex_destroy(&impl->mutex_);
+ pthread_cond_destroy(&impl->condition_);
+ WebPSafeFree(impl);
worker->impl_ = NULL;
}
#else
diff --git a/media/libwebp/utils/thread_utils.h b/media/libwebp/utils/thread_utils.h
index 840831185..0e88c2470 100644
--- a/media/libwebp/utils/thread_utils.h
+++ b/media/libwebp/utils/thread_utils.h
@@ -11,8 +11,8 @@
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifndef WEBP_UTILS_THREAD_H_
-#define WEBP_UTILS_THREAD_H_
+#ifndef WEBP_UTILS_THREAD_UTILS_H_
+#define WEBP_UTILS_THREAD_UTILS_H_
#ifdef HAVE_CONFIG_H
#include "../webp/config.h"
@@ -35,12 +35,9 @@ typedef enum {
// arguments (data1 and data2), and should return false in case of error.
typedef int (*WebPWorkerHook)(void*, void*);
-// Platform-dependent implementation details for the worker.
-typedef struct WebPWorkerImpl WebPWorkerImpl;
-
// Synchronization object used to launch job in the worker thread
typedef struct {
- WebPWorkerImpl* impl_;
+ void* impl_; // platform-dependent implementation worker details
WebPWorkerStatus status_;
WebPWorkerHook hook; // hook to call
void* data1; // first argument passed to 'hook'
@@ -78,11 +75,11 @@ typedef struct {
// decoding takes place. The contents of the interface struct are copied, it
// is safe to free the corresponding memory after this call. This function is
// not thread-safe. Return false in case of invalid pointer or methods.
-WEBP_EXTERN(int) WebPSetWorkerInterface(
+WEBP_EXTERN int WebPSetWorkerInterface(
const WebPWorkerInterface* const winterface);
// Retrieve the currently set thread worker interface.
-WEBP_EXTERN(const WebPWorkerInterface*) WebPGetWorkerInterface(void);
+WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void);
//------------------------------------------------------------------------------
@@ -90,4 +87,4 @@ WEBP_EXTERN(const WebPWorkerInterface*) WebPGetWorkerInterface(void);
} // extern "C"
#endif
-#endif /* WEBP_UTILS_THREAD_H_ */
+#endif /* WEBP_UTILS_THREAD_UTILS_H_ */
diff --git a/media/libwebp/utils/utils.c b/media/libwebp/utils/utils.c
index 504d924b6..9bda6a716 100644
--- a/media/libwebp/utils/utils.c
+++ b/media/libwebp/utils/utils.c
@@ -16,7 +16,8 @@
#include "../webp/decode.h"
#include "../webp/encode.h"
#include "../webp/format_constants.h" // for MAX_PALETTE_SIZE
-#include "./utils.h"
+#include "../utils/color_cache_utils.h"
+#include "../utils/utils.h"
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
@@ -252,7 +253,6 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
int num_colors = 0;
uint8_t in_use[COLOR_HASH_SIZE] = { 0 };
uint32_t colors[COLOR_HASH_SIZE];
- static const uint64_t kHashMul = 0x1e35a7bdull;
const uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
@@ -267,7 +267,7 @@ int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
continue;
}
last_pix = argb[x];
- key = ((last_pix * kHashMul) & 0xffffffffu) >> COLOR_HASH_RIGHT_SHIFT;
+ key = VP8LHashPix(last_pix, COLOR_HASH_RIGHT_SHIFT);
while (1) {
if (!in_use[key]) {
colors[key] = last_pix;
diff --git a/media/libwebp/utils/utils.h b/media/libwebp/utils/utils.h
index 3ab459050..27dc7e090 100644
--- a/media/libwebp/utils/utils.h
+++ b/media/libwebp/utils/utils.h
@@ -48,13 +48,13 @@ extern "C" {
// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
// safe malloc() borrows the signature from calloc(), pointing at the dangerous
// underlying multiply involved.
-WEBP_EXTERN(void*) WebPSafeMalloc(uint64_t nmemb, size_t size);
+WEBP_EXTERN void* WebPSafeMalloc(uint64_t nmemb, size_t size);
// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
-WEBP_EXTERN(void*) WebPSafeCalloc(uint64_t nmemb, size_t size);
+WEBP_EXTERN void* WebPSafeCalloc(uint64_t nmemb, size_t size);
// Companion deallocation function to the above allocations.
-WEBP_EXTERN(void) WebPSafeFree(void* const ptr);
+WEBP_EXTERN void WebPSafeFree(void* const ptr);
//------------------------------------------------------------------------------
// Alignment
@@ -66,7 +66,7 @@ WEBP_EXTERN(void) WebPSafeFree(void* const ptr);
// memcpy() is the safe way of moving potentially unaligned 32b memory.
static WEBP_INLINE uint32_t WebPMemToUint32(const uint8_t* const ptr) {
uint32_t A;
- memcpy(&A, (const int*)ptr, sizeof(A));
+ memcpy(&A, ptr, sizeof(A));
return A;
}
static WEBP_INLINE void WebPUint32ToMem(uint8_t* const ptr, uint32_t val) {
@@ -112,12 +112,12 @@ static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
#define WEBP_NEED_LOG_TABLE_8BIT
extern const uint8_t WebPLogTable8bit[256];
static WEBP_INLINE int WebPLog2FloorC(uint32_t n) {
- int log = 0;
+ int log_value = 0;
while (n >= 256) {
- log += 8;
+ log_value += 8;
n >>= 8;
}
- return log + WebPLogTable8bit[n];
+ return log_value + WebPLogTable8bit[n];
}
// Returns (int)floor(log2(n)). n must be > 0.
@@ -147,14 +147,14 @@ static WEBP_INLINE int BitsLog2Floor(uint32_t n) { return WebPLog2FloorC(n); }
struct WebPPicture;
// Copy width x height pixels from 'src' to 'dst' honoring the strides.
-WEBP_EXTERN(void) WebPCopyPlane(const uint8_t* src, int src_stride,
- uint8_t* dst, int dst_stride,
- int width, int height);
+WEBP_EXTERN void WebPCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height);
// Copy ARGB pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are
// assumed to be already allocated and using ARGB data.
-WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
- struct WebPPicture* const dst);
+WEBP_EXTERN void WebPCopyPixels(const struct WebPPicture* const src,
+ struct WebPPicture* const dst);
//------------------------------------------------------------------------------
// Unique colors.
@@ -166,8 +166,8 @@ WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
// MAX_PALETTE_SIZE, also outputs the actual unique colors into 'palette'.
// Note: 'palette' is assumed to be an array already allocated with at least
// MAX_PALETTE_SIZE elements.
-WEBP_EXTERN(int) WebPGetColorPalette(const struct WebPPicture* const pic,
- uint32_t* const palette);
+WEBP_EXTERN int WebPGetColorPalette(const struct WebPPicture* const pic,
+ uint32_t* const palette);
//------------------------------------------------------------------------------
diff --git a/media/libwebp/webp/decode.h b/media/libwebp/webp/decode.h
index 4c5e74ac3..2165e96c9 100644
--- a/media/libwebp/webp/decode.h
+++ b/media/libwebp/webp/decode.h
@@ -36,39 +36,39 @@ typedef struct WebPDecoderConfig WebPDecoderConfig;
// Return the decoder's version number, packed in hexadecimal using 8bits for
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN(int) WebPGetDecoderVersion(void);
+WEBP_EXTERN int WebPGetDecoderVersion(void);
// Retrieve basic header information: width, height.
// 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.
-WEBP_EXTERN(int) WebPGetInfo(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_EXTERN int WebPGetInfo(const uint8_t* data, size_t data_size,
+ int* width, int* height);
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// with the dimensions in *width and *height. The ordering of samples in
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
// The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error.
-WEBP_EXTERN(uint8_t*) WebPDecodeRGBA(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
+ int* width, int* height);
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
-WEBP_EXTERN(uint8_t*) WebPDecodeARGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
-WEBP_EXTERN(uint8_t*) WebPDecodeBGRA(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
+ int* width, int* height);
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
// If the bitstream contains transparency, it is ignored.
-WEBP_EXTERN(uint8_t*) WebPDecodeRGB(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
-WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size,
- int* width, int* height);
+WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
+ int* width, int* height);
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
@@ -80,13 +80,13 @@ WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size,
// have a common stride returned as '*uv_stride'.
// Return NULL in case of error.
// (*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr
-WEBP_EXTERN(uint8_t*) WebPDecodeYUV(const uint8_t* data, size_t data_size,
- int* width, int* height,
- uint8_t** u, uint8_t** v,
- int* stride, int* uv_stride);
+WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
+ int* width, int* height,
+ uint8_t** u, uint8_t** v,
+ int* stride, int* uv_stride);
// Releases memory returned by the WebPDecode*() functions above.
-WEBP_EXTERN(void) WebPFree(void* ptr);
+WEBP_EXTERN void WebPFree(void* ptr);
// These five functions are variants of the above ones, that decode the image
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
@@ -96,22 +96,22 @@ WEBP_EXTERN(void) WebPFree(void* ptr);
// The parameter 'output_stride' specifies the distance (in bytes)
// between scanlines. Hence, output_buffer_size is expected to be at least
// output_stride x picture-height.
-WEBP_EXTERN(uint8_t*) WebPDecodeRGBAInto(
+WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN(uint8_t*) WebPDecodeARGBInto(
+WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN(uint8_t*) WebPDecodeBGRAInto(
+WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
// RGB and BGR variants. Here too the transparency information, if present,
// will be dropped and ignored.
-WEBP_EXTERN(uint8_t*) WebPDecodeRGBInto(
+WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
-WEBP_EXTERN(uint8_t*) WebPDecodeBGRInto(
+WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
const uint8_t* data, size_t data_size,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@@ -122,7 +122,7 @@ WEBP_EXTERN(uint8_t*) WebPDecodeBGRInto(
// 'u_size' and 'v_size' respectively.
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
// during decoding (or because some buffers were found to be too small).
-WEBP_EXTERN(uint8_t*) WebPDecodeYUVInto(
+WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
const uint8_t* data, size_t data_size,
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
@@ -213,7 +213,7 @@ struct WebPDecBuffer {
};
// Internal, version-checked, entry point
-WEBP_EXTERN(int) WebPInitDecBufferInternal(WebPDecBuffer*, int);
+WEBP_EXTERN int WebPInitDecBufferInternal(WebPDecBuffer*, int);
// Initialize the structure as empty. Must be called before any other use.
// Returns false in case of version mismatch
@@ -223,7 +223,7 @@ static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
// Free any memory associated with the buffer. Must always be called last.
// Note: doesn't free the 'buffer' structure itself.
-WEBP_EXTERN(void) WebPFreeDecBuffer(WebPDecBuffer* buffer);
+WEBP_EXTERN void WebPFreeDecBuffer(WebPDecBuffer* buffer);
//------------------------------------------------------------------------------
// Enumeration of the status codes
@@ -277,7 +277,7 @@ typedef enum VP8StatusCode {
// within valid bounds.
// All other fields of WebPDecBuffer MUST remain constant between calls.
// Returns NULL if the allocation failed.
-WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
+WEBP_EXTERN WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer);
// This function allocates and initializes an incremental-decoder object, which
// will output the RGB/A samples specified by 'csp' into a preallocated
@@ -289,7 +289,7 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
// colorspace 'csp' is taken into account for allocating this buffer. All other
// parameters are ignored.
// Returns NULL if the allocation failed, or if some parameters are invalid.
-WEBP_EXTERN(WebPIDecoder*) WebPINewRGB(
+WEBP_EXTERN WebPIDecoder* WebPINewRGB(
WEBP_CSP_MODE csp,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
@@ -304,7 +304,7 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewRGB(
// In this case, the output buffer will be automatically allocated (using
// MODE_YUVA) when decoding starts. All parameters are then ignored.
// Returns NULL if the allocation failed or if a parameter is invalid.
-WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA(
+WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride,
@@ -312,19 +312,19 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA(
// Deprecated version of the above, without the alpha plane.
// Kept for backward compatibility.
-WEBP_EXTERN(WebPIDecoder*) WebPINewYUV(
+WEBP_EXTERN WebPIDecoder* WebPINewYUV(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride);
// Deletes the WebPIDecoder object and associated memory. Must always be called
// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
-WEBP_EXTERN(void) WebPIDelete(WebPIDecoder* idec);
+WEBP_EXTERN void WebPIDelete(WebPIDecoder* idec);
// Copies and decodes the next available data. Returns VP8_STATUS_OK when
// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
// data is expected. Returns error in other cases.
-WEBP_EXTERN(VP8StatusCode) WebPIAppend(
+WEBP_EXTERN VP8StatusCode WebPIAppend(
WebPIDecoder* idec, const uint8_t* data, size_t data_size);
// A variant of the above function to be used when data buffer contains
@@ -332,7 +332,7 @@ WEBP_EXTERN(VP8StatusCode) WebPIAppend(
// to the internal memory.
// Note that the value of the 'data' pointer can change between calls to
// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
-WEBP_EXTERN(VP8StatusCode) WebPIUpdate(
+WEBP_EXTERN VP8StatusCode WebPIUpdate(
WebPIDecoder* idec, const uint8_t* data, size_t data_size);
// Returns the RGB/A image decoded so far. Returns NULL if output params
@@ -340,15 +340,16 @@ WEBP_EXTERN(VP8StatusCode) WebPIUpdate(
// specified during call to WebPINewDecoder() or WebPINewRGB().
// *last_y is the index of last decoded row in raster scan order. Some pointers
// (*last_y, *width etc.) can be NULL if corresponding information is not
-// needed.
-WEBP_EXTERN(uint8_t*) WebPIDecGetRGB(
+// needed. The values in these pointers are only valid on successful (non-NULL)
+// return.
+WEBP_EXTERN uint8_t* WebPIDecGetRGB(
const WebPIDecoder* idec, int* last_y,
int* width, int* height, int* stride);
// Same as above function to get a YUVA image. Returns pointer to the luma
// plane or NULL in case of error. If there is no alpha information
// the alpha pointer '*a' will be returned NULL.
-WEBP_EXTERN(uint8_t*) WebPIDecGetYUVA(
+WEBP_EXTERN uint8_t* WebPIDecGetYUVA(
const WebPIDecoder* idec, int* last_y,
uint8_t** u, uint8_t** v, uint8_t** a,
int* width, int* height, int* stride, int* uv_stride, int* a_stride);
@@ -368,7 +369,7 @@ static WEBP_INLINE uint8_t* WebPIDecGetYUV(
// Returns NULL in case the incremental decoder object is in an invalid state.
// Otherwise returns the pointer to the internal representation. This structure
// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
-WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea(
+WEBP_EXTERN const WebPDecBuffer* WebPIDecodedArea(
const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
//------------------------------------------------------------------------------
@@ -416,7 +417,7 @@ struct WebPBitstreamFeatures {
};
// Internal, version-checked, entry point
-WEBP_EXTERN(VP8StatusCode) WebPGetFeaturesInternal(
+WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(
const uint8_t*, size_t, WebPBitstreamFeatures*, int);
// Retrieve features from the bitstream. The *features structure is filled
@@ -457,7 +458,7 @@ struct WebPDecoderConfig {
};
// Internal, version-checked, entry point
-WEBP_EXTERN(int) WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
+WEBP_EXTERN int WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
// Initialize the configuration as empty. This function must always be
// called first, unless WebPGetFeatures() is to be called.
@@ -477,14 +478,14 @@ static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
// Returns NULL in case of error (and config->status will then reflect
// the error condition, if available).
-WEBP_EXTERN(WebPIDecoder*) WebPIDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config);
+WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
+ WebPDecoderConfig* config);
// Non-incremental version. This version decodes the full data at once, taking
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
// if the decoding was successful). Note that 'config' cannot be NULL.
-WEBP_EXTERN(VP8StatusCode) WebPDecode(const uint8_t* data, size_t data_size,
- WebPDecoderConfig* config);
+WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
+ WebPDecoderConfig* config);
#ifdef __cplusplus
} // extern "C"
diff --git a/media/libwebp/webp/demux.h b/media/libwebp/webp/demux.h
index 454f6914b..555d64133 100644
--- a/media/libwebp/webp/demux.h
+++ b/media/libwebp/webp/demux.h
@@ -71,7 +71,7 @@ typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions;
// Returns the version number of the demux library, packed in hexadecimal using
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN(int) WebPGetDemuxVersion(void);
+WEBP_EXTERN int WebPGetDemuxVersion(void);
//------------------------------------------------------------------------------
// Life of a Demux object
@@ -85,7 +85,7 @@ typedef enum WebPDemuxState {
} WebPDemuxState;
// Internal, version-checked, entry point
-WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal(
+WEBP_EXTERN WebPDemuxer* WebPDemuxInternal(
const WebPData*, int, WebPDemuxState*, int);
// Parses the full WebP file given by 'data'. For single images the WebP file
@@ -109,27 +109,32 @@ static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
}
// Frees memory associated with 'dmux'.
-WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux);
+WEBP_EXTERN void WebPDemuxDelete(WebPDemuxer* dmux);
//------------------------------------------------------------------------------
// Data/information extraction.
typedef enum WebPFormatFeature {
- WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk.
+ WEBP_FF_FORMAT_FLAGS, // bit-wise combination of WebPFeatureFlags
+ // corresponding to the 'VP8X' chunk (if present).
WEBP_FF_CANVAS_WIDTH,
WEBP_FF_CANVAS_HEIGHT,
- WEBP_FF_LOOP_COUNT,
- WEBP_FF_BACKGROUND_COLOR,
- WEBP_FF_FRAME_COUNT // Number of frames present in the demux object.
- // In case of a partial demux, this is the number of
- // frames seen so far, with the last frame possibly
- // being partial.
+ WEBP_FF_LOOP_COUNT, // only relevant for animated file
+ WEBP_FF_BACKGROUND_COLOR, // idem.
+ WEBP_FF_FRAME_COUNT // Number of frames present in the demux object.
+ // In case of a partial demux, this is the number
+ // of frames seen so far, with the last frame
+ // possibly being partial.
} WebPFormatFeature;
// Get the 'feature' value from the 'dmux'.
// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
// returned a state > WEBP_DEMUX_PARSING_HEADER.
-WEBP_EXTERN(uint32_t) WebPDemuxGetI(
+// If 'feature' is WEBP_FF_FORMAT_FLAGS, the returned value is a bit-wise
+// combination of WebPFeatureFlags values.
+// If 'feature' is WEBP_FF_LOOP_COUNT, WEBP_FF_BACKGROUND_COLOR, the returned
+// value is only meaningful if the bitstream is animated.
+WEBP_EXTERN uint32_t WebPDemuxGetI(
const WebPDemuxer* dmux, WebPFormatFeature feature);
//------------------------------------------------------------------------------
@@ -159,20 +164,20 @@ struct WebPIterator {
// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of 'iter'.
-WEBP_EXTERN(int) WebPDemuxGetFrame(
+WEBP_EXTERN int WebPDemuxGetFrame(
const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
// previous ('iter->frame_num' - 1) frame. These functions do not loop.
// Returns true on success, false otherwise.
-WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter);
-WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter);
+WEBP_EXTERN int WebPDemuxNextFrame(WebPIterator* iter);
+WEBP_EXTERN int WebPDemuxPrevFrame(WebPIterator* iter);
// Releases any memory associated with 'iter'.
// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
// iter. Also, must be called before destroying the associated WebPDemuxer with
// WebPDemuxDelete().
-WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter);
+WEBP_EXTERN void WebPDemuxReleaseIterator(WebPIterator* iter);
//------------------------------------------------------------------------------
// Chunk iteration.
@@ -197,20 +202,20 @@ struct WebPChunkIterator {
// payloads are accessed through WebPDemuxGetFrame() and related functions.
// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
// NOTE: 'dmux' must persist for the lifetime of the iterator.
-WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux,
- const char fourcc[4], int chunk_number,
- WebPChunkIterator* iter);
+WEBP_EXTERN int WebPDemuxGetChunk(const WebPDemuxer* dmux,
+ const char fourcc[4], int chunk_number,
+ WebPChunkIterator* iter);
// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
// ('iter->chunk_num' - 1) chunk. These functions do not loop.
// Returns true on success, false otherwise.
-WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter);
-WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);
+WEBP_EXTERN int WebPDemuxNextChunk(WebPChunkIterator* iter);
+WEBP_EXTERN int WebPDemuxPrevChunk(WebPChunkIterator* iter);
// Releases any memory associated with 'iter'.
// Must be called before destroying the associated WebPDemuxer with
// WebPDemuxDelete().
-WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
+WEBP_EXTERN void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
//------------------------------------------------------------------------------
// WebPAnimDecoder API
@@ -252,7 +257,7 @@ struct WebPAnimDecoderOptions {
};
// Internal, version-checked, entry point.
-WEBP_EXTERN(int) WebPAnimDecoderOptionsInitInternal(
+WEBP_EXTERN int WebPAnimDecoderOptionsInitInternal(
WebPAnimDecoderOptions*, int);
// Should always be called, to initialize a fresh WebPAnimDecoderOptions
@@ -266,7 +271,7 @@ static WEBP_INLINE int WebPAnimDecoderOptionsInit(
}
// Internal, version-checked, entry point.
-WEBP_EXTERN(WebPAnimDecoder*) WebPAnimDecoderNewInternal(
+WEBP_EXTERN WebPAnimDecoder* WebPAnimDecoderNewInternal(
const WebPData*, const WebPAnimDecoderOptions*, int);
// Creates and initializes a WebPAnimDecoder object.
@@ -301,8 +306,8 @@ struct WebPAnimInfo {
// info - (out) global information fetched from the animation.
// Returns:
// True on success.
-WEBP_EXTERN(int) WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
- WebPAnimInfo* info);
+WEBP_EXTERN int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
+ WebPAnimInfo* info);
// Fetch the next frame from 'dec' based on options supplied to
// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
@@ -316,8 +321,8 @@ WEBP_EXTERN(int) WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
// Returns:
// False if any of the arguments are NULL, or if there is a parsing or
// decoding error, or if there are no more frames. Otherwise, returns true.
-WEBP_EXTERN(int) WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
- uint8_t** buf, int* timestamp);
+WEBP_EXTERN int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
+ uint8_t** buf, int* timestamp);
// Check if there are more frames left to decode.
// Parameters:
@@ -325,7 +330,7 @@ WEBP_EXTERN(int) WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
// Returns:
// True if 'dec' is not NULL and some frames are yet to be decoded.
// Otherwise, returns false.
-WEBP_EXTERN(int) WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
+WEBP_EXTERN int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
// Resets the WebPAnimDecoder object, so that next call to
// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
@@ -333,7 +338,7 @@ WEBP_EXTERN(int) WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
// info.loop_count times) without destroying and recreating the 'dec' object.
// Parameters:
// dec - (in/out) decoder instance to be reset
-WEBP_EXTERN(void) WebPAnimDecoderReset(WebPAnimDecoder* dec);
+WEBP_EXTERN void WebPAnimDecoderReset(WebPAnimDecoder* dec);
// Grab the internal demuxer object.
// Getting the demuxer object can be useful if one wants to use operations only
@@ -343,13 +348,13 @@ WEBP_EXTERN(void) WebPAnimDecoderReset(WebPAnimDecoder* dec);
//
// Parameters:
// dec - (in) decoder instance from which the demuxer object is to be fetched.
-WEBP_EXTERN(const WebPDemuxer*) WebPAnimDecoderGetDemuxer(
+WEBP_EXTERN const WebPDemuxer* WebPAnimDecoderGetDemuxer(
const WebPAnimDecoder* dec);
// Deletes the WebPAnimDecoder object.
// Parameters:
// dec - (in/out) decoder instance to be deleted
-WEBP_EXTERN(void) WebPAnimDecoderDelete(WebPAnimDecoder* dec);
+WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
#ifdef __cplusplus
} // extern "C"
diff --git a/media/libwebp/webp/encode.h b/media/libwebp/webp/encode.h
index 35fde1d05..7ec3543dc 100644
--- a/media/libwebp/webp/encode.h
+++ b/media/libwebp/webp/encode.h
@@ -35,7 +35,7 @@ typedef struct WebPMemoryWriter WebPMemoryWriter;
// Return the encoder's version number, packed in hexadecimal using 8bits for
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN(int) WebPGetEncoderVersion(void);
+WEBP_EXTERN int WebPGetEncoderVersion(void);
//------------------------------------------------------------------------------
// One-stop-shop call! No questions asked:
@@ -46,37 +46,37 @@ WEBP_EXTERN(int) WebPGetEncoderVersion(void);
// These functions compress using the lossy format, and the quality_factor
// can go from 0 (smaller output, lower quality) to 100 (best quality,
// larger output).
-WEBP_EXTERN(size_t) WebPEncodeRGB(const uint8_t* rgb,
+WEBP_EXTERN size_t WebPEncodeRGB(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+WEBP_EXTERN size_t WebPEncodeBGR(const uint8_t* bgr,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+WEBP_EXTERN size_t WebPEncodeRGBA(const uint8_t* rgba,
int width, int height, int stride,
float quality_factor, uint8_t** output);
-WEBP_EXTERN(size_t) WebPEncodeBGR(const uint8_t* bgr,
+WEBP_EXTERN size_t WebPEncodeBGRA(const uint8_t* bgra,
int width, int height, int stride,
float quality_factor, uint8_t** output);
-WEBP_EXTERN(size_t) WebPEncodeRGBA(const uint8_t* rgba,
- int width, int height, int stride,
- float quality_factor, uint8_t** output);
-WEBP_EXTERN(size_t) WebPEncodeBGRA(const uint8_t* bgra,
- int width, int height, int stride,
- float quality_factor, uint8_t** output);
// These functions are the equivalent of the above, but compressing in a
// lossless manner. Files are usually larger than lossy format, but will
// not suffer any compression loss.
-WEBP_EXTERN(size_t) WebPEncodeLosslessRGB(const uint8_t* rgb,
+WEBP_EXTERN size_t WebPEncodeLosslessRGB(const uint8_t* rgb,
+ int width, int height, int stride,
+ uint8_t** output);
+WEBP_EXTERN size_t WebPEncodeLosslessBGR(const uint8_t* bgr,
+ int width, int height, int stride,
+ uint8_t** output);
+WEBP_EXTERN size_t WebPEncodeLosslessRGBA(const uint8_t* rgba,
int width, int height, int stride,
uint8_t** output);
-WEBP_EXTERN(size_t) WebPEncodeLosslessBGR(const uint8_t* bgr,
+WEBP_EXTERN size_t WebPEncodeLosslessBGRA(const uint8_t* bgra,
int width, int height, int stride,
uint8_t** output);
-WEBP_EXTERN(size_t) WebPEncodeLosslessRGBA(const uint8_t* rgba,
- int width, int height, int stride,
- uint8_t** output);
-WEBP_EXTERN(size_t) WebPEncodeLosslessBGRA(const uint8_t* bgra,
- int width, int height, int stride,
- uint8_t** output);
// Releases memory returned by the WebPEncode*() functions above.
-WEBP_EXTERN(void) WebPFree(void* ptr);
+WEBP_EXTERN void WebPFree(void* ptr);
//------------------------------------------------------------------------------
// Coding parameters
@@ -93,12 +93,15 @@ typedef enum WebPImageHint {
// Compression parameters.
struct WebPConfig {
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
- float quality; // between 0 (smallest file) and 100 (biggest)
+ float quality; // between 0 and 100. For lossy, 0 gives the smallest
+ // size and 100 the largest. For lossless, this
+ // parameter is the amount of effort put into the
+ // compression: 0 is the fastest but gives larger
+ // files compared to the slowest, but best, 100.
int method; // quality/speed trade-off (0=fast, 6=slower-better)
WebPImageHint image_hint; // Hint for image type (lossless only for now).
- // Parameters related to lossy compression only:
int target_size; // if non-zero, set the desired target size in bytes.
// Takes precedence over the 'compression' parameter.
float target_PSNR; // if non-zero, specifies the minimal distortion to
@@ -159,7 +162,7 @@ typedef enum WebPPreset {
} WebPPreset;
// Internal, version-checked, entry point
-WEBP_EXTERN(int) WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
+WEBP_EXTERN int WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
// Should always be called, to initialize a fresh WebPConfig structure before
// modification. Returns false in case of version mismatch. WebPConfigInit()
@@ -186,15 +189,15 @@ static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
// speed and final compressed size.
// This function will overwrite several fields from config: 'method', 'quality'
// and 'lossless'. Returns false in case of parameter error.
-WEBP_EXTERN(int) WebPConfigLosslessPreset(WebPConfig* config, int level);
+WEBP_EXTERN int WebPConfigLosslessPreset(WebPConfig* config, int level);
// Returns true if 'config' is non-NULL and all configuration parameters are
// within their valid ranges.
-WEBP_EXTERN(int) WebPValidateConfig(const WebPConfig* config);
+WEBP_EXTERN int WebPValidateConfig(const WebPConfig* config);
//------------------------------------------------------------------------------
// Input / Output
-// Structure for storing auxiliary statistics (mostly for lossy encoding).
+// Structure for storing auxiliary statistics.
struct WebPAuxStats {
int coded_size; // final size
@@ -242,16 +245,16 @@ struct WebPMemoryWriter {
};
// The following must be called first before any use.
-WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer);
+WEBP_EXTERN void WebPMemoryWriterInit(WebPMemoryWriter* writer);
// The following must be called to deallocate writer->mem memory. The 'writer'
// object itself is not deallocated.
-WEBP_EXTERN(void) WebPMemoryWriterClear(WebPMemoryWriter* writer);
+WEBP_EXTERN void WebPMemoryWriterClear(WebPMemoryWriter* writer);
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
// completion, writer.mem and writer.size will hold the coded data.
// writer.mem must be freed by calling WebPMemoryWriterClear.
-WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
- const WebPPicture* picture);
+WEBP_EXTERN int WebPMemoryWrite(const uint8_t* data, size_t data_size,
+ const WebPPicture* picture);
// Progress hook, called from time to time to report progress. It can return
// false to request an abort of the encoding process, or true otherwise if
@@ -354,7 +357,7 @@ struct WebPPicture {
};
// Internal, version-checked, entry point
-WEBP_EXTERN(int) WebPPictureInitInternal(WebPPicture*, int);
+WEBP_EXTERN int WebPPictureInitInternal(WebPPicture*, int);
// Should always be called, to initialize the structure. Returns false in case
// of version mismatch. WebPPictureInit() must have succeeded before using the
@@ -371,20 +374,20 @@ static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
// Allocate y/u/v buffers as per colorspace/width/height specification.
// Note! This function will free the previous buffer if needed.
// Returns false in case of memory error.
-WEBP_EXTERN(int) WebPPictureAlloc(WebPPicture* picture);
+WEBP_EXTERN int WebPPictureAlloc(WebPPicture* picture);
// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
// Note that this function does _not_ free the memory used by the 'picture'
// object itself.
// Besides memory (which is reclaimed) all other fields of 'picture' are
// preserved.
-WEBP_EXTERN(void) WebPPictureFree(WebPPicture* picture);
+WEBP_EXTERN void WebPPictureFree(WebPPicture* picture);
// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, *dst
// will fully own the copied pixels (this is not a view). The 'dst' picture need
// not be initialized as its content is overwritten.
// Returns false in case of memory allocation error.
-WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
+WEBP_EXTERN int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
// Compute the single distortion for packed planes of samples.
// 'src' will be compared to 'ref', and the raw distortion stored into
@@ -393,19 +396,19 @@ WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
// 'x_step' is the horizontal stride (in bytes) between samples.
// 'src/ref_stride' is the byte distance between rows.
// Returns false in case of error (bad parameter, memory allocation error, ...).
-WEBP_EXTERN(int) WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
- const uint8_t* ref, size_t ref_stride,
- int width, int height,
- size_t x_step,
- int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
- float* distortion, float* result);
+WEBP_EXTERN int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
+ const uint8_t* ref, size_t ref_stride,
+ int width, int height,
+ size_t x_step,
+ int type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
+ float* distortion, float* result);
// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
// are in dB, stored in result[] in the B/G/R/A/All order. The distortion is
// always performed using ARGB samples. Hence if the input is YUV(A), the
// picture will be internally converted to ARGB (just for the measurement).
// Warning: this function is rather CPU-intensive.
-WEBP_EXTERN(int) WebPPictureDistortion(
+WEBP_EXTERN int WebPPictureDistortion(
const WebPPicture* src, const WebPPicture* ref,
int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
float result[5]);
@@ -418,8 +421,8 @@ WEBP_EXTERN(int) WebPPictureDistortion(
// must be fully be comprised inside the 'src' source picture. If the source
// picture uses the YUV420 colorspace, the top and left coordinates will be
// snapped to even values.
-WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture,
- int left, int top, int width, int height);
+WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
+ int left, int top, int width, int height);
// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
// is defined by the top-left corner pixel coordinates (left, top) as well
@@ -432,42 +435,42 @@ WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture,
// with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten.
// Returns false in case of memory allocation error or invalid parameters.
-WEBP_EXTERN(int) WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst);
+WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
+ int left, int top, int width, int height,
+ WebPPicture* dst);
// Returns true if the 'picture' is actually a view and therefore does
// not own the memory for pixels.
-WEBP_EXTERN(int) WebPPictureIsView(const WebPPicture* picture);
+WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
// Rescale a picture to new dimension width x height.
// If either 'width' or 'height' (but not both) is 0 the corresponding
// dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
-WEBP_EXTERN(int) WebPPictureRescale(WebPPicture* pic, int width, int height);
+WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height);
// Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any.
// *rgb buffer should have a size of at least height * rgb_stride.
// Returns false in case of memory error.
-WEBP_EXTERN(int) WebPPictureImportRGB(
+WEBP_EXTERN int WebPPictureImportRGB(
WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
// Same, but for RGBA buffer.
-WEBP_EXTERN(int) WebPPictureImportRGBA(
+WEBP_EXTERN int WebPPictureImportRGBA(
WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
// input buffer ignoring the alpha channel. Avoids needing to copy the data
// to a temporary 24-bit RGB buffer to import the RGB only.
-WEBP_EXTERN(int) WebPPictureImportRGBX(
+WEBP_EXTERN int WebPPictureImportRGBX(
WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
// Variants of the above, but taking BGR(A|X) input.
-WEBP_EXTERN(int) WebPPictureImportBGR(
+WEBP_EXTERN int WebPPictureImportBGR(
WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
-WEBP_EXTERN(int) WebPPictureImportBGRA(
+WEBP_EXTERN int WebPPictureImportBGRA(
WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
-WEBP_EXTERN(int) WebPPictureImportBGRX(
+WEBP_EXTERN int WebPPictureImportBGRX(
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
// Converts picture->argb data to the YUV420A format. The 'colorspace'
@@ -476,14 +479,14 @@ WEBP_EXTERN(int) WebPPictureImportBGRX(
// non-opaque transparent values is detected, and 'colorspace' will be
// adjusted accordingly. Note that this method is lossy.
// Returns false in case of error.
-WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture,
- WebPEncCSP /*colorspace = WEBP_YUV420*/);
+WEBP_EXTERN int WebPPictureARGBToYUVA(WebPPicture* picture,
+ WebPEncCSP /*colorspace = WEBP_YUV420*/);
// Same as WebPPictureARGBToYUVA(), but the conversion is done using
// pseudo-random dithering with a strength 'dithering' between
// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
// for photographic picture.
-WEBP_EXTERN(int) WebPPictureARGBToYUVADithered(
+WEBP_EXTERN int WebPPictureARGBToYUVADithered(
WebPPicture* picture, WebPEncCSP colorspace, float dithering);
// Performs 'sharp' RGBA->YUVA420 downsampling and colorspace conversion.
@@ -491,9 +494,9 @@ WEBP_EXTERN(int) WebPPictureARGBToYUVADithered(
// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
// and sharper YUV representation.
// Returns false in case of error.
-WEBP_EXTERN(int) WebPPictureSharpARGBToYUVA(WebPPicture* picture);
+WEBP_EXTERN int WebPPictureSharpARGBToYUVA(WebPPicture* picture);
// kept for backward compatibility:
-WEBP_EXTERN(int) WebPPictureSmartARGBToYUVA(WebPPicture* picture);
+WEBP_EXTERN int WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
// The input format must be YUV_420 or YUV_420A. The conversion from YUV420 to
@@ -501,22 +504,22 @@ WEBP_EXTERN(int) WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Note that the use of this colorspace is discouraged if one has access to the
// raw ARGB samples, since using YUV420 is comparatively lossy.
// Returns false in case of error.
-WEBP_EXTERN(int) WebPPictureYUVAToARGB(WebPPicture* picture);
+WEBP_EXTERN int WebPPictureYUVAToARGB(WebPPicture* picture);
// Helper function: given a width x height plane of RGBA or YUV(A) samples
-// clean-up the YUV or RGB samples under fully transparent area, to help
-// compressibility (no guarantee, though).
-WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* picture);
+// clean-up or smoothen the YUV or RGB samples under fully transparent area,
+// to help compressibility (no guarantee, though).
+WEBP_EXTERN void WebPCleanupTransparentArea(WebPPicture* picture);
// Scan the picture 'picture' for the presence of non fully opaque alpha values.
// Returns true in such case. Otherwise returns false (indicating that the
// alpha plane can be ignored altogether e.g.).
-WEBP_EXTERN(int) WebPPictureHasTransparency(const WebPPicture* picture);
+WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture);
// Remove the transparency information (if present) by blending the color with
// the background color 'background_rgb' (specified as 24bit RGB triplet).
// After this call, all alpha values are reset to 0xff.
-WEBP_EXTERN(void) WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
+WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
//------------------------------------------------------------------------------
// Main call
@@ -531,7 +534,7 @@ WEBP_EXTERN(void) WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
// the former for lossy encoding, and the latter for lossless encoding
// (when config.lossless is true). Automatic conversion from one format to
// another is provided but they both incur some loss.
-WEBP_EXTERN(int) WebPEncode(const WebPConfig* config, WebPPicture* picture);
+WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
//------------------------------------------------------------------------------
diff --git a/media/libwebp/webp/mux.h b/media/libwebp/webp/mux.h
index daccc65e8..28bb4a41c 100644
--- a/media/libwebp/webp/mux.h
+++ b/media/libwebp/webp/mux.h
@@ -98,13 +98,13 @@ typedef enum WebPChunkId {
// Returns the version number of the mux library, packed in hexadecimal using
// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
-WEBP_EXTERN(int) WebPGetMuxVersion(void);
+WEBP_EXTERN int WebPGetMuxVersion(void);
//------------------------------------------------------------------------------
// Life of a Mux object
// Internal, version-checked, entry point
-WEBP_EXTERN(WebPMux*) WebPNewInternal(int);
+WEBP_EXTERN WebPMux* WebPNewInternal(int);
// Creates an empty mux object.
// Returns:
@@ -117,13 +117,13 @@ static WEBP_INLINE WebPMux* WebPMuxNew(void) {
// Deletes the mux object.
// Parameters:
// mux - (in/out) object to be deleted
-WEBP_EXTERN(void) WebPMuxDelete(WebPMux* mux);
+WEBP_EXTERN void WebPMuxDelete(WebPMux* mux);
//------------------------------------------------------------------------------
// Mux creation.
// Internal, version-checked, entry point
-WEBP_EXTERN(WebPMux*) WebPMuxCreateInternal(const WebPData*, int, int);
+WEBP_EXTERN WebPMux* WebPMuxCreateInternal(const WebPData*, int, int);
// Creates a mux object from raw data given in WebP RIFF format.
// Parameters:
@@ -160,7 +160,7 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
// or if fourcc corresponds to an image chunk.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk(
+WEBP_EXTERN WebPMuxError WebPMuxSetChunk(
WebPMux* mux, const char fourcc[4], const WebPData* chunk_data,
int copy_data);
@@ -176,7 +176,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk(
// or if fourcc corresponds to an image chunk.
// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given id.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk(
+WEBP_EXTERN WebPMuxError WebPMuxGetChunk(
const WebPMux* mux, const char fourcc[4], WebPData* chunk_data);
// Deletes the chunk with the given 'fourcc' from the mux object.
@@ -189,7 +189,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk(
// or if fourcc corresponds to an image chunk.
// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given fourcc.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxDeleteChunk(
+WEBP_EXTERN WebPMuxError WebPMuxDeleteChunk(
WebPMux* mux, const char fourcc[4]);
//------------------------------------------------------------------------------
@@ -222,7 +222,7 @@ struct WebPMuxFrameInfo {
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
+WEBP_EXTERN WebPMuxError WebPMuxSetImage(
WebPMux* mux, const WebPData* bitstream, int copy_data);
// Adds a frame at the end of the mux object.
@@ -241,7 +241,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
// or if content of 'frame' is invalid.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame(
+WEBP_EXTERN WebPMuxError WebPMuxPushFrame(
WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data);
// Gets the nth frame from the mux object.
@@ -259,7 +259,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame(
// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
+WEBP_EXTERN WebPMuxError WebPMuxGetFrame(
const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame);
// Deletes a frame from the mux object.
@@ -272,7 +272,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object
// before deletion.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
+WEBP_EXTERN WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
//------------------------------------------------------------------------------
// Animation.
@@ -296,7 +296,7 @@ struct WebPMuxAnimParams {
// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetAnimationParams(
+WEBP_EXTERN WebPMuxError WebPMuxSetAnimationParams(
WebPMux* mux, const WebPMuxAnimParams* params);
// Gets the animation parameters from the mux object.
@@ -307,7 +307,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetAnimationParams(
// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
// WEBP_MUX_NOT_FOUND - if ANIM chunk is not present in mux object.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetAnimationParams(
+WEBP_EXTERN WebPMuxError WebPMuxGetAnimationParams(
const WebPMux* mux, WebPMuxAnimParams* params);
//------------------------------------------------------------------------------
@@ -328,8 +328,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetAnimationParams(
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL; or
// width or height are invalid or out of bounds
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetCanvasSize(WebPMux* mux,
- int width, int height);
+WEBP_EXTERN WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux,
+ int width, int height);
// Gets the canvas size from the mux object.
// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
@@ -343,8 +343,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetCanvasSize(WebPMux* mux,
// WEBP_MUX_INVALID_ARGUMENT - if mux, width or height is NULL.
// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux,
- int* width, int* height);
+WEBP_EXTERN WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux,
+ int* width, int* height);
// Gets the feature flags from the mux object.
// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
@@ -359,8 +359,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux,
// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL.
// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
- uint32_t* flags);
+WEBP_EXTERN WebPMuxError WebPMuxGetFeatures(const WebPMux* mux,
+ uint32_t* flags);
// Gets number of chunks with the given 'id' in the mux object.
// Parameters:
@@ -370,8 +370,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
// Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux, or num_elements is NULL.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
- WebPChunkId id, int* num_elements);
+WEBP_EXTERN WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
+ WebPChunkId id, int* num_elements);
// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'.
// This function also validates the mux object.
@@ -388,8 +388,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
// WEBP_MUX_INVALID_ARGUMENT - if mux or assembled_data is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxAssemble(WebPMux* mux,
- WebPData* assembled_data);
+WEBP_EXTERN WebPMuxError WebPMuxAssemble(WebPMux* mux,
+ WebPData* assembled_data);
//------------------------------------------------------------------------------
// WebPAnimEncoder API
@@ -442,7 +442,7 @@ struct WebPAnimEncoderOptions {
};
// Internal, version-checked, entry point.
-WEBP_EXTERN(int) WebPAnimEncoderOptionsInitInternal(
+WEBP_EXTERN int WebPAnimEncoderOptionsInitInternal(
WebPAnimEncoderOptions*, int);
// Should always be called, to initialize a fresh WebPAnimEncoderOptions
@@ -455,7 +455,7 @@ static WEBP_INLINE int WebPAnimEncoderOptionsInit(
}
// Internal, version-checked, entry point.
-WEBP_EXTERN(WebPAnimEncoder*) WebPAnimEncoderNewInternal(
+WEBP_EXTERN WebPAnimEncoder* WebPAnimEncoderNewInternal(
int, int, const WebPAnimEncoderOptions*, int);
// Creates and initializes a WebPAnimEncoder object.
@@ -490,7 +490,7 @@ static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
// Returns:
// On error, returns false and frame->error_code is set appropriately.
// Otherwise, returns true.
-WEBP_EXTERN(int) WebPAnimEncoderAdd(
+WEBP_EXTERN int WebPAnimEncoderAdd(
WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
const struct WebPConfig* config);
@@ -503,8 +503,8 @@ WEBP_EXTERN(int) WebPAnimEncoderAdd(
// webp_data - (out) generated WebP bitstream.
// Returns:
// True on success.
-WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
- WebPData* webp_data);
+WEBP_EXTERN int WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
+ WebPData* webp_data);
// Get error string corresponding to the most recent call using 'enc'. The
// returned string is owned by 'enc' and is valid only until the next call to
@@ -514,12 +514,12 @@ WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
// Returns:
// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call
// to 'enc' had an error, or an empty string if the last call was a success.
-WEBP_EXTERN(const char*) WebPAnimEncoderGetError(WebPAnimEncoder* enc);
+WEBP_EXTERN const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc);
// Deletes the WebPAnimEncoder object.
// Parameters:
// enc - (in/out) object to be deleted
-WEBP_EXTERN(void) WebPAnimEncoderDelete(WebPAnimEncoder* enc);
+WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
//------------------------------------------------------------------------------
diff --git a/media/libwebp/webp/types.h b/media/libwebp/webp/types.h
index 98fff35a1..989a763f0 100644
--- a/media/libwebp/webp/types.h
+++ b/media/libwebp/webp/types.h
@@ -40,9 +40,9 @@ typedef long long int int64_t;
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
# if defined(__GNUC__) && __GNUC__ >= 4
-# define WEBP_EXTERN(type) extern __attribute__ ((visibility ("default"))) type
+# define WEBP_EXTERN extern __attribute__ ((visibility ("default")))
# else
-# define WEBP_EXTERN(type) extern type
+# define WEBP_EXTERN extern
# endif /* __GNUC__ >= 4 */
#endif /* WEBP_EXTERN */
diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in
index 188682d3b..af4a155a9 100644
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -217,7 +217,6 @@
@BINPATH@/components/toolkit_finalizationwitness.xpt
@BINPATH@/components/toolkit_formautofill.xpt
@BINPATH@/components/toolkit_osfile.xpt
-@BINPATH@/components/toolkit_securityreporter.xpt
@BINPATH@/components/toolkit_perfmonitoring.xpt
@BINPATH@/components/toolkit_xulstore.xpt
@BINPATH@/components/toolkitprofile.xpt
@@ -422,10 +421,6 @@
@BINPATH@/components/PrivateBrowsing.manifest
@BINPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
-; Security Reports
-@BINPATH@/components/SecurityReporter.manifest
-@BINPATH@/components/SecurityReporter.js
-
; [Browser Chrome Files]
@BINPATH@/chrome/toolkit@JAREXT@
@BINPATH@/chrome/toolkit.manifest
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 8ef75e360..ddff087ed 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -208,6 +208,10 @@ pref("dom.enable_performance_observer", false);
// Enable requestIdleCallback API
pref("dom.requestIdleCallback.enabled", true);
+// Enable Intersection Observers
+// See WD https://w3c.github.io/IntersectionObserver/
+pref("dom.IntersectionObserver.enabled", true);
+
// Whether the Gamepad API is enabled
pref("dom.gamepad.enabled", true);
pref("dom.gamepad.test.enabled", false);
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index 7bcec146d..ac855b478 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -24,7 +24,6 @@
#include "nsICryptoHash.h"
#include "nsINetworkInterceptController.h"
#include "nsINSSErrorsService.h"
-#include "nsISecurityReporter.h"
#include "nsIStringBundle.h"
#include "nsIStreamListenerTee.h"
#include "nsISeekableStream.h"
@@ -1733,56 +1732,6 @@ nsHttpChannel::ProcessContentSignatureHeader(nsHttpResponseHead *aResponseHead)
return NS_OK;
}
-/**
- * Decide whether or not to send a security report and, if so, give the
- * SecurityReporter the information required to send such a report.
- */
-void
-nsHttpChannel::ProcessSecurityReport(nsresult status) {
- uint32_t errorClass;
- nsCOMPtr<nsINSSErrorsService> errSvc =
- do_GetService("@mozilla.org/nss_errors_service;1");
- // getErrorClass will throw a generic NS_ERROR_FAILURE if the error code is
- // not in the set of errors covered by the NSS errors service.
- nsresult rv = errSvc->GetErrorClass(status, &errorClass);
- if (!NS_SUCCEEDED(rv)) {
- return;
- }
-
- // if the content was not loaded succesfully and we have security info,
- // send a TLS error report - we must do this early as other parts of
- // OnStopRequest can return early
- bool reportingEnabled =
- Preferences::GetBool("security.ssl.errorReporting.enabled");
- bool reportingAutomatic =
- Preferences::GetBool("security.ssl.errorReporting.automatic");
- if (!mSecurityInfo || !reportingEnabled || !reportingAutomatic) {
- return;
- }
-
- nsCOMPtr<nsITransportSecurityInfo> secInfo =
- do_QueryInterface(mSecurityInfo);
- nsCOMPtr<nsISecurityReporter> errorReporter =
- do_GetService("@mozilla.org/securityreporter;1");
-
- if (!secInfo || !mURI) {
- return;
- }
-
- nsAutoCString hostStr;
- int32_t port;
- rv = mURI->GetHost(hostStr);
- if (!NS_SUCCEEDED(rv)) {
- return;
- }
-
- rv = mURI->GetPort(&port);
-
- if (NS_SUCCEEDED(rv)) {
- errorReporter->ReportTLSError(secInfo, hostStr, port);
- }
-}
-
bool
nsHttpChannel::IsHTTPS()
{
@@ -6687,10 +6636,6 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
MOZ_ASSERT(NS_IsMainThread(),
"OnStopRequest should only be called from the main thread");
- if (NS_FAILED(status)) {
- ProcessSecurityReport(status);
- }
-
// If this load failed because of a security error, it may be because we
// are in a captive portal - trigger an async check to make sure.
int32_t nsprError = -1 * NS_ERROR_GET_CODE(status);
diff --git a/netwerk/sctp/datachannel/DataChannel.cpp b/netwerk/sctp/datachannel/DataChannel.cpp
index d47a9d5ea..f2a91c589 100644
--- a/netwerk/sctp/datachannel/DataChannel.cpp
+++ b/netwerk/sctp/datachannel/DataChannel.cpp
@@ -654,7 +654,10 @@ int
DataChannelConnection::SendPacket(unsigned char data[], size_t len, bool release)
{
//LOG(("%p: SCTP/DTLS sent %ld bytes", this, len));
- int res = mTransportFlow->SendPacket(data, len) < 0 ? 1 : 0;
+ int res = 0;
+ if (mTransportFlow) {
+ res = mTransportFlow->SendPacket(data, len) < 0 ? 1 : 0;
+ }
if (release)
delete [] data;
return res;
diff --git a/netwerk/sctp/datachannel/DataChannel.h b/netwerk/sctp/datachannel/DataChannel.h
index 84ab422fc..ebf29366b 100644
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -111,7 +111,7 @@ public:
virtual void NotifyDataChannel(already_AddRefed<DataChannel> channel) = 0;
};
- explicit DataChannelConnection(DataConnectionListener *listener);
+ DataChannelConnection(DataConnectionListener *listener);
bool Init(unsigned short aPort, uint16_t aNumStreams, bool aUsingDtls);
void Destroy(); // So we can spawn refs tied to runnables in shutdown
diff --git a/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js b/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js
deleted file mode 100644
index d7ffd17bd..000000000
--- a/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/* -*- 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/. */
-
-/* This test is for the TLS error reporting functionality exposed by
- * SecurityReporter.js in /toolkit/components/securityreporter. The test is
- * here because we make use of the tlsserver functionality that lives with the
- * PSM ssl tests.
- *
- * The testing here will be augmented by the existing mochitests for the
- * error reporting functionality in aboutNetError.xhtml and
- * aboutCertError.xhtml once these make use of this component.
- */
-
-"use strict";
-const CC = Components.Constructor;
-const Cm = Components.manager;
-
-Cu.import("resource://testing-common/AppInfo.jsm");
-/*global updateAppInfo:false*/ // Imported via AppInfo.jsm.
-updateAppInfo();
-
-// We must get the profile before performing operations on the cert db.
-do_get_profile();
-
-const certdb = Cc["@mozilla.org/security/x509certdb;1"]
- .getService(Ci.nsIX509CertDB);
-const reporter = Cc["@mozilla.org/securityreporter;1"]
- .getService(Ci.nsISecurityReporter);
-
-
-const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
- "nsIBinaryInputStream", "setInputStream");
-
-var server;
-
-// this allows us to create a callback which checks that a report is as
-// expected.
-function getReportCheck(expectReport, expectedError) {
- return function sendReportWithInfo(transportSecurityInfo) {
- // register a path handler on the server
- server.registerPathHandler("/submit/sslreports",
- function(request, response) {
- if (expectReport) {
- let report = JSON.parse(readDataFromRequest(request));
- do_check_eq(report.errorCode, expectedError);
- response.setStatusLine(null, 201, "Created");
- response.write("Created");
- } else {
- do_throw("No report should have been received");
- }
- });
-
- reporter.reportTLSError(transportSecurityInfo, "example.com", -1);
- };
-}
-
-// read the request body from a request
-function readDataFromRequest(aRequest) {
- if (aRequest.method == "POST" || aRequest.method == "PUT") {
- if (aRequest.bodyInputStream) {
- let inputStream = new BinaryInputStream(aRequest.bodyInputStream);
- let bytes = [];
- let available;
-
- while ((available = inputStream.available()) > 0) {
- Array.prototype.push.apply(bytes, inputStream.readByteArray(available));
- }
-
- return String.fromCharCode.apply(null, bytes);
- }
- }
- return null;
-}
-
-function run_test() {
- // start a report server
- server = new HttpServer();
- server.start(-1);
-
- let port = server.identity.primaryPort;
-
- // Set the reporting URL to ensure any reports are sent to the test server
- Services.prefs.setCharPref("security.ssl.errorReporting.url",
- `http://localhost:${port}/submit/sslreports`);
- // set strict-mode pinning enforcement so we can cause connection failures.
- Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
-
- // start a TLS server
- add_tls_server_setup("BadCertServer", "bad_certs");
-
- // Add a user-specified trust anchor.
- addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
-
-
- // Cause a reportable condition with error reporting disabled. No report
- // should be sent.
- Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false);
- add_connection_test("expired.example.com",
- SEC_ERROR_EXPIRED_CERTIFICATE, null,
- getReportCheck(false));
-
- // Now enable reporting
- add_test(function () {
- Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
- run_next_test();
- });
-
- // test calling the component with no transportSecurityInfo. No report should
- // be sent even though reporting is enabled.
- add_test(function() {
- server.registerPathHandler("/submit/sslreports",
- function(request, response) {
- do_throw("No report should be sent");
- });
- reporter.reportTLSError(null, "example.com", -1);
- run_next_test();
- });
-
- // Test sending a report with no error. This allows us to check the case
- // where there is no failed cert chain
- add_connection_test("good.include-subdomains.pinning.example.com",
- PRErrorCodeSuccess, null,
- getReportCheck(true, PRErrorCodeSuccess));
-
- // Test sending a report where there is an error and a failed cert chain.
- add_connection_test("expired.example.com",
- SEC_ERROR_EXPIRED_CERTIFICATE, null,
- getReportCheck(true, SEC_ERROR_EXPIRED_CERTIFICATE));
-
- run_next_test();
-}
diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini
index b2f3de420..bdf9933f4 100644
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -144,6 +144,3 @@ skip-if = toolkit == 'android'
[test_validity.js]
run-sequentially = hardcoded ports
[test_x509.js]
-
-# The TLS error reporting functionality lives in /toolkit but needs tlsserver
-[test_toolkit_securityreporter.js]
diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build
index c11f62792..953e6c6e3 100644
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -51,7 +51,6 @@ DIRS += [
'reader',
'remotebrowserutils',
'reflect',
- 'securityreporter',
'sqlite',
'startup',
'statusfilter',
diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js
index bd5cebfc4..327ebbdf8 100644
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -727,10 +727,12 @@ function escapeKeyHandler() {
window.close();
}
-#if defined(MC_BASILISK) && defined(XP_WIN)
+#ifdef XP_WIN
+#if defined(MC_BASILISK) || defined(HYPE_ICEWEASEL)
function OpenMigrator() {
const { MigrationUtils } = Cu.import("resource:///modules/MigrationUtils.jsm", {});
// We pass in the type of source we're using for use in telemetry:
MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_PASSWORDS]);
}
#endif
+#endif
diff --git a/toolkit/components/passwordmgr/content/passwordManager.xul b/toolkit/components/passwordmgr/content/passwordManager.xul
index c0a10bf8e..8590d96ac 100644
--- a/toolkit/components/passwordmgr/content/passwordManager.xul
+++ b/toolkit/components/passwordmgr/content/passwordManager.xul
@@ -112,11 +112,13 @@
<button id="removeAllSignons" icon="clear"
oncommand="DeleteAllSignons();"/>
<spacer flex="1"/>
-#if defined(MC_BASILISK) && defined(XP_WIN)
+#ifdef XP_WIN
+#if defined(MC_BASILISK) || defined(HYPE_ICEWEASEL)
<button accesskey="&import.accesskey;"
label="&import.label;"
oncommand="OpenMigrator();"/>
#endif
+#endif
<button id="togglePasswords"
oncommand="TogglePasswordVisible();"/>
</hbox>
diff --git a/toolkit/components/securityreporter/SecurityReporter.js b/toolkit/components/securityreporter/SecurityReporter.js
deleted file mode 100644
index 9ca1e5546..000000000
--- a/toolkit/components/securityreporter/SecurityReporter.js
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- 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} = Components;
-
-Cu.importGlobalProperties(['fetch']);
-
-const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
-const protocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
- .getService(Ci.nsIHttpProtocolHandler);
-const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-
-const TLS_ERROR_REPORT_TELEMETRY_SUCCESS = 6;
-const TLS_ERROR_REPORT_TELEMETRY_FAILURE = 7;
-const HISTOGRAM_ID = "TLS_ERROR_REPORT_UI";
-
-
-XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
- "resource://gre/modules/UpdateUtils.jsm");
-
-function getDERString(cert)
-{
- var length = {};
- var derArray = cert.getRawDER(length);
- var derString = '';
- for (var i = 0; i < derArray.length; i++) {
- derString += String.fromCharCode(derArray[i]);
- }
- return derString;
-}
-
-function SecurityReporter() { }
-
-SecurityReporter.prototype = {
- classDescription: "Security reporter component",
- classID: Components.ID("{8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b}"),
- contractID: "@mozilla.org/securityreporter;1",
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISecurityReporter]),
- reportTLSError: function(transportSecurityInfo, hostname, port) {
- // don't send if there's no transportSecurityInfo (since the report cannot
- // contain anything of interest)
- if (!transportSecurityInfo) {
- return;
- }
-
- // don't send a report if the pref is not enabled
- if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
- return;
- }
-
- // Don't send a report if the host we're connecting to is the report
- // server (otherwise we'll get loops when this fails)
- let endpoint =
- Services.prefs.getCharPref("security.ssl.errorReporting.url");
- let reportURI = Services.io.newURI(endpoint, null, null);
-
- if (reportURI.host == hostname) {
- return;
- }
-
- // Convert the nsIX509CertList into a format that can be parsed into
- // JSON
- let asciiCertChain = [];
-
- if (transportSecurityInfo.failedCertChain) {
- let certs = transportSecurityInfo.failedCertChain.getEnumerator();
- while (certs.hasMoreElements()) {
- let cert = certs.getNext();
- cert.QueryInterface(Ci.nsIX509Cert);
- asciiCertChain.push(btoa(getDERString(cert)));
- }
- }
-
- let report = {
- hostname: hostname,
- port: port,
- timestamp: Math.round(Date.now() / 1000),
- errorCode: transportSecurityInfo.errorCode,
- failedCertChain: asciiCertChain,
- userAgent: protocolHandler.userAgent,
- version: 1,
- build: Services.appinfo.appBuildID,
- product: Services.appinfo.name,
- channel: UpdateUtils.UpdateChannel
- }
-
- fetch(endpoint, {
- method: "POST",
- body: JSON.stringify(report),
- headers: {
- 'Content-Type': 'application/json'
- }
- }).then(function (aResponse) {
- if (!aResponse.ok) {
- // request returned non-success status
- Services.telemetry.getHistogramById(HISTOGRAM_ID)
- .add(TLS_ERROR_REPORT_TELEMETRY_FAILURE);
- } else {
- Services.telemetry.getHistogramById(HISTOGRAM_ID)
- .add(TLS_ERROR_REPORT_TELEMETRY_SUCCESS);
- }
- }).catch(function (e) {
- // error making request to reportURL
- Services.telemetry.getHistogramById(HISTOGRAM_ID)
- .add(TLS_ERROR_REPORT_TELEMETRY_FAILURE);
- });
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecurityReporter]);
diff --git a/toolkit/components/securityreporter/SecurityReporter.manifest b/toolkit/components/securityreporter/SecurityReporter.manifest
deleted file mode 100644
index d4e080dc7..000000000
--- a/toolkit/components/securityreporter/SecurityReporter.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b} SecurityReporter.js
-contract @mozilla.org/securityreporter;1 {8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b}
diff --git a/toolkit/components/securityreporter/moz.build b/toolkit/components/securityreporter/moz.build
deleted file mode 100644
index 7ef56a115..000000000
--- a/toolkit/components/securityreporter/moz.build
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-XPIDL_MODULE = 'toolkit_securityreporter'
-
-XPIDL_SOURCES += [
- 'nsISecurityReporter.idl',
-]
-
-EXTRA_COMPONENTS += [
- 'SecurityReporter.js',
- 'SecurityReporter.manifest',
-]
diff --git a/toolkit/components/securityreporter/nsISecurityReporter.idl b/toolkit/components/securityreporter/nsISecurityReporter.idl
deleted file mode 100644
index 462dd1e48..000000000
--- a/toolkit/components/securityreporter/nsISecurityReporter.idl
+++ /dev/null
@@ -1,14 +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/. */
-
-#include "nsISupports.idl"
-#include "nsITransportSecurityInfo.idl"
-
-[scriptable, uuid(8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b)]
-interface nsISecurityReporter : nsISupports
-{
- void reportTLSError(in nsITransportSecurityInfo aSecurityInfo,
- in AUTF8String aHostname,
- in long aPort);
-};
diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js
index 016549f43..4e42a5687 100644
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -879,16 +879,25 @@ function populateActionBox() {
}
}
-// Prompt user to restart the browser in safe mode
-function safeModeRestart() {
+// Prompt user to restart the browser
+function restart(safeMode) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
- if (!cancelQuit.data) {
- Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
+ if (cancelQuit.data) {
+ return;
+ }
+
+ let flags = Ci.nsIAppStartup.eAttemptQuit;
+
+ if (safeMode) {
+ Services.startup.restartInSafeMode(flags);
+ } else {
+ Services.startup.quit(flags | Ci.nsIAppStartup.eRestart);
}
}
+
/**
* Set up event listeners for buttons.
*/
@@ -915,9 +924,12 @@ function setupEventListeners() {
if (Services.obs.enumerateObservers("restart-in-safe-mode").hasMoreElements()) {
Services.obs.notifyObservers(null, "restart-in-safe-mode", "");
} else {
- safeModeRestart();
+ restart(true);
}
});
+ $("restart-button").addEventListener("click", function(event) {
+ restart(false);
+ });
$("verify-place-integrity-button").addEventListener("click", function(event) {
PlacesDBUtils.checkAndFixDatabase(function(aLog) {
let msg = aLog.join("\n");
diff --git a/toolkit/content/aboutSupport.xhtml b/toolkit/content/aboutSupport.xhtml
index a92dcfb4a..5eb64d437 100644
--- a/toolkit/content/aboutSupport.xhtml
+++ b/toolkit/content/aboutSupport.xhtml
@@ -44,6 +44,12 @@
&aboutSupport.restartInSafeMode.label;
</button>
</div>
+ <div id="restart-box">
+ <h3>&aboutSupport.restartTitle;</h3>
+ <button id="restart-button">
+ &aboutSupport.restartNormal.label;
+ </button>
+ </div>
</div>
<h1>
diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
index c8dd6dc47..0c0f9494a 100644
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -57,8 +57,6 @@ toolkit.jar:
#endif
content/global/filepicker.properties
content/global/globalOverlay.js
- content/global/memoriam.xhtml
-* content/global/mozilla.css
content/global/mozilla.xhtml
#ifdef MOZ_PHOENIX
content/global/logopage.xhtml
diff --git a/toolkit/content/memoriam.xhtml b/toolkit/content/memoriam.xhtml
deleted file mode 100644
index f1a1b474d..000000000
--- a/toolkit/content/memoriam.xhtml
+++ /dev/null
@@ -1,76 +0,0 @@
-<!DOCTYPE html
-[
- <!ENTITY % directionDTD SYSTEM "chrome://global/locale/global.dtd" >
- %directionDTD;
- <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
- %brandDTD;
-]>
-
-<!-- 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/. -->
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset='utf-8' />
- <title>Mozilla: In Memoriam</title>
-
-<style>
-html {
- background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat;
- color: white;
- font-style: italic;
- text-rendering: optimizeLegibility;
- min-height: 100%;
-}
-
-#moztext {
- margin-top: 15%;
- font-size: 1.1em;
- font-family: serif;
- text-align: center;
- line-height: 1.5;
-}
-
-#from {
- font-size: 1.0em;
- font-family: serif;
- text-align: right;
-}
-
-em {
- font-size: 1.3em;
- line-height: 0;
-}
-
-a {
- text-decoration: none;
- color: white;
-}
-</style>
-</head>
-
-<body dir="&locale.dir;">
-
-<section>
- <p id="moztext">
- <h1>Mozilla: In Memoriam</h1>
- <br/>
- Dedicated to the tireless developers who have come and gone.<br/>
- To those who have put their heart and soul into Mozilla products.<br/>
- To those who have seen their good intentions and hard work squandered.<br/>
- To those who really cared about the user, and cared about usability.<br/>
- To those who truly understood us and desired freedom, but were unheard.<br/>
- To those who knew that change is inevitable, but loss of vision is not.<br/>
- To those who were forced to give up the good fight.<br/>
- <br/>
- <em>Thank you.</em> &brandFullName; would not have been possible without you.<br/>
- <br/>
- </p>
-
- <p id="from">
- </p>
-</section>
-
-</body>
-</html> \ No newline at end of file
diff --git a/toolkit/content/mozilla.css b/toolkit/content/mozilla.css
deleted file mode 100644
index d5eae6415..000000000
--- a/toolkit/content/mozilla.css
+++ /dev/null
@@ -1,36 +0,0 @@
-html {
-%ifdef MC_PALEMOON
- background: #333399 radial-gradient( circle at 75% 25%, #6666b0 0%, #333399 40%, #111177 80%) center center / cover no-repeat;
-%else
- background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat;
-%endif
-
- color: white;
- font-style: italic;
- text-rendering: optimizeLegibility;
- min-height: 100%;
-}
-
-#moztext {
- margin-top: 15%;
- font-size: 1.1em;
- font-family: serif;
- text-align: center;
- line-height: 1.5;
-}
-
-#from {
- font-size: 1.95em;
- font-family: serif;
- text-align: right;
-}
-
-em {
- font-size: 1.3em;
- line-height: 0;
-}
-
-a {
- text-decoration: none;
- color: white;
-} \ No newline at end of file
diff --git a/toolkit/content/mozilla.xhtml b/toolkit/content/mozilla.xhtml
index 8c79b5ff9..f1a1b474d 100644
--- a/toolkit/content/mozilla.xhtml
+++ b/toolkit/content/mozilla.xhtml
@@ -1,9 +1,9 @@
<!DOCTYPE html
[
- <!ENTITY % mozillaDTD SYSTEM "chrome://global/locale/mozilla.dtd" >
- %mozillaDTD;
<!ENTITY % directionDTD SYSTEM "chrome://global/locale/global.dtd" >
%directionDTD;
+ <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+ %brandDTD;
]>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
@@ -13,23 +13,64 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset='utf-8' />
- <title>&chronicles.title.55.2;</title>
+ <title>Mozilla: In Memoriam</title>
- <link rel="stylesheet" href="chrome://global/content/mozilla.css"
- type="text/css"/>
+<style>
+html {
+ background: maroon radial-gradient( circle, #a01010 0%, #800000 80%) center center / cover no-repeat;
+ color: white;
+ font-style: italic;
+ text-rendering: optimizeLegibility;
+ min-height: 100%;
+}
+
+#moztext {
+ margin-top: 15%;
+ font-size: 1.1em;
+ font-family: serif;
+ text-align: center;
+ line-height: 1.5;
+}
+
+#from {
+ font-size: 1.0em;
+ font-family: serif;
+ text-align: right;
+}
+
+em {
+ font-size: 1.3em;
+ line-height: 0;
+}
+
+a {
+ text-decoration: none;
+ color: white;
+}
+</style>
</head>
<body dir="&locale.dir;">
<section>
<p id="moztext">
- &chronicles.quote.55.2;
+ <h1>Mozilla: In Memoriam</h1>
+ <br/>
+ Dedicated to the tireless developers who have come and gone.<br/>
+ To those who have put their heart and soul into Mozilla products.<br/>
+ To those who have seen their good intentions and hard work squandered.<br/>
+ To those who really cared about the user, and cared about usability.<br/>
+ To those who truly understood us and desired freedom, but were unheard.<br/>
+ To those who knew that change is inevitable, but loss of vision is not.<br/>
+ To those who were forced to give up the good fight.<br/>
+ <br/>
+ <em>Thank you.</em> &brandFullName; would not have been possible without you.<br/>
+ <br/>
</p>
<p id="from">
- &chronicles.from.55.2;
</p>
</section>
</body>
-</html>
+</html> \ No newline at end of file
diff --git a/toolkit/locales/en-US/chrome/global/aboutProfiles.dtd b/toolkit/locales/en-US/chrome/global/aboutProfiles.dtd
index 48e24923e..5091517b2 100644
--- a/toolkit/locales/en-US/chrome/global/aboutProfiles.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutProfiles.dtd
@@ -6,5 +6,5 @@
<!ENTITY aboutProfiles.subtitle "This page helps you to manage your profiles. Each profile is a separate world which contains separate history, bookmarks, settings and add-ons.">
<!ENTITY aboutProfiles.create "Create a New Profile">
<!ENTITY aboutProfiles.restart.title "Restart">
-<!ENTITY aboutProfiles.restart.inSafeMode "Restart with Add-ons Disabled…">
+<!ENTITY aboutProfiles.restart.inSafeMode "Restart in Safe Mode…">
<!ENTITY aboutProfiles.restart.normal "Restart normally…">
diff --git a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
index 8459300c5..a0dd3531b 100644
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
@@ -110,7 +110,10 @@ variant of aboutSupport.showDir.label. -->
<!ENTITY aboutSupport.copyRawDataToClipboard.label "Copy raw data to clipboard">
<!ENTITY aboutSupport.safeModeTitle "Try Safe Mode">
-<!ENTITY aboutSupport.restartInSafeMode.label "Restart with Add-ons Disabled…">
+<!ENTITY aboutSupport.restartInSafeMode.label "Restart in Safe Mode…">
+
+<!ENTITY aboutSupport.restartTitle "Try Restart">
+<!ENTITY aboutSupport.restartNormal.label "Restart normally…">
<!ENTITY aboutSupport.graphicsFeaturesTitle "Features">
<!ENTITY aboutSupport.graphicsDiagnosticsTitle "Diagnostics">
diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn
index 23b9d72fb..e92e10599 100644
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -67,7 +67,6 @@
locale/@AB_CD@/global/intl.properties (%chrome/global/intl.properties)
locale/@AB_CD@/global/keys.properties (%chrome/global/keys.properties)
locale/@AB_CD@/global/languageNames.properties (%chrome/global/languageNames.properties)
- locale/@AB_CD@/global/mozilla.dtd (%chrome/global/mozilla.dtd)
#ifndef MOZ_FENNEC
locale/@AB_CD@/global/narrate.properties (%chrome/global/narrate.properties)
#endif
diff --git a/toolkit/modules/NewTabUtils.jsm b/toolkit/modules/NewTabUtils.jsm
index e452a6fb2..548d87dda 100644
--- a/toolkit/modules/NewTabUtils.jsm
+++ b/toolkit/modules/NewTabUtils.jsm
@@ -249,7 +249,7 @@ var AllPages = {
* Returns whether the history tiles are enhanced.
*/
get enhanced() {
-#ifdef MC_BASILISK
+#if defined(MC_BASILISK) || defined(HYPE_ICEWEASEL)
// Hard-block the use of sponsored tiles.
return false;
#else
diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm
index 20aad6770..a862b1db4 100644
--- a/toolkit/modules/Troubleshoot.jsm
+++ b/toolkit/modules/Troubleshoot.jsm
@@ -347,11 +347,14 @@ var dataProviders = {
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils)
data.supportsHardwareH264 = "Unknown";
- let promise = winUtils.supportsHardwareH264Decoding;
- promise.then(function(v) {
- data.supportsHardwareH264 = v;
- });
- promises.push(promise);
+ try {
+ // After restart - data may not be available
+ let promise = winUtils.supportsHardwareH264Decoding;
+ promise.then(function(v) {
+ data.supportsHardwareH264 = v;
+ });
+ promises.push(promise);
+ } catch (e) {}
data.currentAudioBackend = winUtils.currentAudioBackend;
@@ -457,7 +460,9 @@ var dataProviders = {
// Eagerly free resources.
let loseExt = gl.getExtension("WEBGL_lose_context");
- loseExt.loseContext();
+ if (loseExt) {
+ loseExt.loseContext();
+ }
return contextInfo;
diff --git a/toolkit/mozapps/installer/package-name.mk b/toolkit/mozapps/installer/package-name.mk
index d88975f36..1a8728088 100644
--- a/toolkit/mozapps/installer/package-name.mk
+++ b/toolkit/mozapps/installer/package-name.mk
@@ -12,10 +12,18 @@ ifndef PACKAGE_NAME_MK_INCLUDED
PACKAGE_NAME_MK_INCLUDED := 1
ifndef MOZ_PKG_VERSION
+# Normally MOZ_PKG_VERSION is set to the application version
+MOZ_PKG_VERSION = $(MOZ_APP_VERSION)
+
+# This overrides it with the BUILDID for Basilisk and IceWeasel
+# We do it this way because makefile's conditional checking is very
+# primitive or else very cryptic
ifdef MC_BASILISK
MOZ_PKG_VERSION = $(BUILDID)
-else
-MOZ_PKG_VERSION = $(MOZ_APP_VERSION)
+endif
+
+ifdef HYPE_ICEWEASEL
+MOZ_PKG_VERSION = $(BUILDID)
endif
endif
diff --git a/toolkit/themes/linux/global/global.css b/toolkit/themes/linux/global/global.css
index 9553725d6..9328f7a66 100644
--- a/toolkit/themes/linux/global/global.css
+++ b/toolkit/themes/linux/global/global.css
@@ -316,7 +316,7 @@ popupnotificationcontent {
/* :::::: Close button icons ::::: */
-%ifdef MC_BASILISK
+%ifdef MOZ_AUSTRALIS
.close-icon {
-moz-appearance: none;
height: 16px;
diff --git a/toolkit/themes/shared/aboutSupport.css b/toolkit/themes/shared/aboutSupport.css
index d26cd3cbd..69e6a95b4 100644
--- a/toolkit/themes/shared/aboutSupport.css
+++ b/toolkit/themes/shared/aboutSupport.css
@@ -99,6 +99,10 @@ td {
width: 30%;
}
+#contents {
+ clear: right;
+}
+
#action-box,
#reset-box,
#safe-mode-box {
diff --git a/toolkit/themes/shared/jar.inc.mn b/toolkit/themes/shared/jar.inc.mn
index 675353409..e361e744f 100644
--- a/toolkit/themes/shared/jar.inc.mn
+++ b/toolkit/themes/shared/jar.inc.mn
@@ -59,7 +59,7 @@ toolkit.jar:
skin/classic/global/reader/RM-Content-Width-Plus-44x16.svg (../../shared/reader/RM-Content-Width-Plus-44x16.svg)
skin/classic/global/reader/RM-Line-Height-Minus-38x14.svg (../../shared/reader/RM-Line-Height-Minus-38x14.svg)
skin/classic/global/reader/RM-Line-Height-Plus-38x24.svg (../../shared/reader/RM-Line-Height-Plus-38x24.svg)
- skin/classic/global/media/TopLevelImageDocument.css (../../shared/media/TopLevelImageDocument.css)
+* skin/classic/global/media/TopLevelImageDocument.css (../../shared/media/TopLevelImageDocument.css)
skin/classic/global/media/TopLevelVideoDocument.css (../../shared/media/TopLevelVideoDocument.css)
skin/classic/global/media/imagedoc-lightnoise.png (../../shared/media/imagedoc-lightnoise.png)
skin/classic/global/media/imagedoc-darknoise.png (../../shared/media/imagedoc-darknoise.png)
diff --git a/toolkit/themes/shared/media/TopLevelImageDocument.css b/toolkit/themes/shared/media/TopLevelImageDocument.css
index 524217516..de970512c 100644
--- a/toolkit/themes/shared/media/TopLevelImageDocument.css
+++ b/toolkit/themes/shared/media/TopLevelImageDocument.css
@@ -5,6 +5,12 @@
@media not print {
/* N.B.: Remember to update ImageDocument.css in the tree or reftests may fail! */
+%ifdef MC_PALEMOON
+ body {
+ color: #eee;
+ background: #2E3B41;
+ }
+%else
body {
color: #eee;
background-image: url("chrome://global/skin/media/imagedoc-darknoise.png");
@@ -14,4 +20,5 @@
background: hsl(0,0%,90%) url("chrome://global/skin/media/imagedoc-lightnoise.png");
color: #222;
}
+%endif
}
diff --git a/toolkit/themes/windows/global/global.css b/toolkit/themes/windows/global/global.css
index 416321041..6b6a21ca3 100644
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -331,7 +331,7 @@ popupnotificationcontent {
/* :::::: Close button icons ::::: */
-%ifdef MC_BASILISK
+%ifdef MOZ_AUSTRALIS
.close-icon {
list-style-image: url("chrome://global/skin/icons/close.png");
-moz-image-region: rect(0, 20px, 20px, 0);
diff --git a/widget/BasicEvents.h b/widget/BasicEvents.h
index a6228f179..960cb67c6 100644
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -161,6 +161,9 @@ public:
}
inline void PreventDefault(bool aCalledByDefaultHandler = true)
{
+ if (!mCancelable) {
+ return;
+ }
mDefaultPrevented = true;
// Note that even if preventDefault() has already been called by chrome,
// a call of preventDefault() by content needs to overwrite
@@ -175,6 +178,9 @@ public:
// This should be used only before dispatching events into the DOM tree.
inline void PreventDefaultBeforeDispatch()
{
+ if (!mCancelable) {
+ return;
+ }
mDefaultPrevented = true;
}
inline bool DefaultPrevented() const
@@ -407,10 +413,16 @@ public:
nsString mSpecifiedEventTypeString;
// Event targets, needed by DOM Events
+ // Note that when you need event target for DOM event, you should use
+ // Get*DOMEventTarget() instead of accessing these members directly.
nsCOMPtr<dom::EventTarget> mTarget;
nsCOMPtr<dom::EventTarget> mCurrentTarget;
nsCOMPtr<dom::EventTarget> mOriginalTarget;
+ dom::EventTarget* GetDOMEventTarget() const;
+ dom::EventTarget* GetCurrentDOMEventTarget() const;
+ dom::EventTarget* GetOriginalDOMEventTarget() const;
+
void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets)
{
// mClass should be initialized with the constructor.
diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp
index 7dd292cb0..59c80672b 100644
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -12,6 +12,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TouchEvents.h"
+#include "nsIDOMEventTarget.h"
#include "nsPrintfCString.h"
namespace mozilla {
@@ -411,6 +412,39 @@ WidgetEvent::IsAllowedToDispatchDOMEvent() const
}
/******************************************************************************
+ * mozilla::WidgetEvent
+ *
+ * Misc methods.
+ ******************************************************************************/
+
+static dom::EventTarget*
+GetTargetForDOMEvent(nsIDOMEventTarget* aTarget)
+{
+ return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
+}
+
+dom::EventTarget*
+WidgetEvent::GetDOMEventTarget() const
+{
+ return GetTargetForDOMEvent(mTarget);
+}
+
+dom::EventTarget*
+WidgetEvent::GetCurrentDOMEventTarget() const
+{
+ return GetTargetForDOMEvent(mCurrentTarget);
+}
+
+dom::EventTarget*
+WidgetEvent::GetOriginalDOMEventTarget() const
+{
+ if (mOriginalTarget) {
+ return GetTargetForDOMEvent(mOriginalTarget);
+ }
+ return GetDOMEventTarget();
+}
+
+/******************************************************************************
* mozilla::WidgetInputEvent
******************************************************************************/