diff options
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 = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + 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), @@ -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(¤tFlags); + editorBase->GetFlags(¤tFlags); 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 @@ -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, ¬_hev); + GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, ¬_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, ¬_hev); + GetNotHEV_SSE2(p1, p0, q0, q1, hev_thresh, ¬_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 ******************************************************************************/ |